git-flight-rules/README_ja.md

2167 lines
92 KiB
Markdown
Raw Normal View History

2020-02-23 08:47:15 +06:00
# Git フライトルール
2020-02-13 09:13:04 +06:00
🌍
2020-02-23 08:47:15 +06:00
*[English](README.md) ∙ [Español](README_es.md) ∙ [Русский](README_ru.md) ∙ [简体中文](README_zh-CN.md)∙ [한국어](README_kr.md) ∙ [Tiếng Việt](README_vi.md) ∙ [Français](README_fr.md) ∙ [日本語](README_ja.md)*
2020-02-13 09:13:04 +06:00
2020-02-23 08:47:15 +06:00
#### フライトルールとは?
2020-02-13 09:13:04 +06:00
2020-02-23 08:47:15 +06:00
宇宙飛行士ここでは、Git を使う開発者)が問題に対処するためのガイドです。
2020-02-13 09:13:04 +06:00
2020-02-23 08:47:15 +06:00
> *フライトルール*は、何か起きたときの手順の一つ一つとその理由を記したマニュアルです。基本的に、シナリオごとに標準的な対処法が事細かに説明されています。[...]
2020-02-13 09:13:04 +06:00
2020-02-23 08:47:15 +06:00
> マーキュリー計画のチームが知見を集め始めた 1960 年代から、NASA は私たちが遭った失敗や災難とその解決策を収集してきました。知見の大全は今や、エンジンの不調からハッチハンドルの故障やコンピュータの不具合に至る問題とその対処法に関する、数千ものリストになりました。
2020-02-13 09:13:04 +06:00
— Chris Hadfield, *An Astronaut's Guide to Life*.
2020-02-23 08:47:15 +06:00
#### この文書で使う記法について
2020-02-13 09:13:04 +06:00
2020-02-23 08:47:15 +06:00
文書の全ての例で、明確さのため、現在のブランチとステージされた編集内容の有無を表示するようカスタマイズされた Bash プロンプトを使います。
ブランチは括弧書きされ、ブランチ名の横の `*` はステージされた編集があることを示します。
2020-02-13 09:13:04 +06:00
2020-02-23 08:47:15 +06:00
全てのコマンドは Git バージョン 2.13.0 から動くはずです。Git のバージョンアップについては [Git のウェブサイト](https://www.git-scm.com/) を参照してください。
2020-02-13 09:13:04 +06:00
[![Join the chat at https://gitter.im/k88hudson/git-flight-rules](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/k88hudson/git-flight-rules?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
2020-02-23 08:47:15 +06:00
2020-02-13 09:13:04 +06:00
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
- [Repositories](#repositories)
- [I want to start a local repository](#i-want-to-start-a-local-repository)
- [I want to clone a remote repository](#i-want-to-clone-a-remote-repository)
- [I set the wrong remote repository](#i-set-the-wrong-remote-repository)
- [I want to add code to someone else's repository](#i-want-to-add-code-to-someone-elses-repository)
- [Suggesting code via pull requests](#suggesting-code-via-pull-requests)
- [I need to update my fork with latest updates from the original repository](#i-need-to-update-my-fork-with-latest-updates-from-the-original-repository)
- [Editing Commits](#editing-commits)
- [What did I just commit?](#what-did-i-just-commit)
- [I wrote the wrong thing in a commit message](#i-wrote-the-wrong-thing-in-a-commit-message)
- [I committed with the wrong name and email configured](#i-committed-with-the-wrong-name-and-email-configured)
- [I want to remove a file from the previous commit](#i-want-to-remove-a-file-from-the-previous-commit)
- [I want to delete or remove my last commit](#i-want-to-delete-or-remove-my-last-commit)
- [Delete/remove arbitrary commit](#deleteremove-arbitrary-commit)
- [I tried to push my amended commit to a remote, but I got an error message](#i-tried-to-push-my-amended-commit-to-a-remote-but-i-got-an-error-message)
- [I accidentally did a hard reset, and I want my changes back](#i-accidentally-did-a-hard-reset-and-i-want-my-changes-back)
- [I accidentally committed and pushed a merge](#i-accidentally-committed-and-pushed-a-merge)
- [I accidentally committed and pushed files containing sensitive data](#i-accidentally-committed-and-pushed-files-containing-sensitive-data)
- [I want to remove a large file from ever existing in repo history](#i-want-to-remove-a-large-file-from-ever-existing-in-repo-history)
- [Recommended Technique: Use third-party bfg](#recommended-technique-use-third-party-bfg)
- [Built-in Technique: Use git-filter-branch](#built-in-technique-use-git-filter-branch)
- [Final Step: Pushing your changed repo history](#final-step-pushing-your-changed-repo-history)
- [I need to change the content of a commit which is not my last](#i-need-to-change-the-content-of-a-commit-which-is-not-my-last)
- [Staging](#staging)
- [I want to stage all tracked files and leave untracked files](#i-want-to-stage-all-tracked-files-and-leave-untracked-files)
- [To stage part of tracked files](#to-stage-part-of-tracked-files)
- [I need to add staged changes to the previous commit](#i-need-to-add-staged-changes-to-the-previous-commit)
- [I want to stage part of a new file, but not the whole file](#i-want-to-stage-part-of-a-new-file-but-not-the-whole-file)
- [I want to add changes in one file to two different commits](#i-want-to-add-changes-in-one-file-to-two-different-commits)
- [I staged too many edits, and I want to break them out into a separate commit](#i-staged-too-many-edits-and-i-want-to-break-them-out-into-a-separate-commit)
- [I want to stage my unstaged edits, and unstage my staged edits](#i-want-to-stage-my-unstaged-edits-and-unstage-my-staged-edits)
- [Unstaged Edits](#unstaged-edits)
- [I want to move my unstaged edits to a new branch](#i-want-to-move-my-unstaged-edits-to-a-new-branch)
- [I want to move my unstaged edits to a different, existing branch](#i-want-to-move-my-unstaged-edits-to-a-different-existing-branch)
- [I want to discard my local uncommitted changes (staged and unstaged)](#i-want-to-discard-my-local-uncommitted-changes-staged-and-unstaged)
- [I want to discard specific unstaged changes](#i-want-to-discard-specific-unstaged-changes)
- [I want to discard specific unstaged files](#i-want-to-discard-specific-unstaged-files)
- [I want to discard only my unstaged local changes](#i-want-to-discard-only-my-unstaged-local-changes)
- [I want to discard all of my untracked files](#i-want-to-discard-all-of-my-untracked-files)
- [I want to unstage a specific staged file](#i-want-to-unstage-a-specific-staged-file)
- [Branches](#branches)
- [I want to list all branches](#i-want-to-list-all-branches)
- [Create a branch from a commit](#create-a-branch-from-a-commit)
- [I pulled from/into the wrong branch](#i-pulled-frominto-the-wrong-branch)
- [I want to discard local commits so my branch is the same as one on the server](#i-want-to-discard-local-commits-so-my-branch-is-the-same-as-one-on-the-server)
- [I committed to master instead of a new branch](#i-committed-to-master-instead-of-a-new-branch)
- [I want to keep the whole file from another ref-ish](#i-want-to-keep-the-whole-file-from-another-ref-ish)
- [I made several commits on a single branch that should be on different branches](#i-made-several-commits-on-a-single-branch-that-should-be-on-different-branches)
- [I want to delete local branches that were deleted upstream](#i-want-to-delete-local-branches-that-were-deleted-upstream)
- [I accidentally deleted my branch](#i-accidentally-deleted-my-branch)
- [I want to delete a branch](#i-want-to-delete-a-branch)
- [I want to delete multiple branches](#i-want-to-delete-multiple-branches)
- [I want to rename a branch](#i-want-to-rename-a-branch)
- [I want to checkout to a remote branch that someone else is working on](#i-want-to-checkout-to-a-remote-branch-that-someone-else-is-working-on)
- [I want to create a new remote branch from current local one](#i-want-to-create-a-new-remote-branch-from-current-local-one)
- [I want to set a remote branch as the upstream for a local branch](#i-want-to-set-a-remote-branch-as-the-upstream-for-a-local-branch)
- [I want to set my HEAD to track the default remote branch](#i-want-to-set-my-head-to-track-the-default-remote-branch)
- [I made changes on the wrong branch](#i-made-changes-on-the-wrong-branch)
- [Rebasing and Merging](#rebasing-and-merging)
- [I want to undo rebase/merge](#i-want-to-undo-rebasemerge)
- [I rebased, but I don't want to force push](#i-rebased-but-i-dont-want-to-force-push)
- [I need to combine commits](#i-need-to-combine-commits)
- [Safe merging strategy](#safe-merging-strategy)
- [I need to merge a branch into a single commit](#i-need-to-merge-a-branch-into-a-single-commit)
- [I want to combine only unpushed commits](#i-want-to-combine-only-unpushed-commits)
- [I need to abort the merge](#i-need-to-abort-the-merge)
- [I need to update the parent commit of my branch](#i-need-to-update-the-parent-commit-of-my-branch)
- [Check if all commits on a branch are merged](#check-if-all-commits-on-a-branch-are-merged)
- [Possible issues with interactive rebases](#possible-issues-with-interactive-rebases)
- [The rebase editing screen says 'noop'](#the-rebase-editing-screen-says-noop)
- [There were conflicts](#there-were-conflicts)
- [Stash](#stash)
- [Stash all edits](#stash-all-edits)
- [Stash specific files](#stash-specific-files)
- [Stash with message](#stash-with-message)
- [Apply a specific stash from list](#apply-a-specific-stash-from-list)
- [Stash while keeping unstaged edits](#stash-while-keeping-unstaged-edits)
- [Finding](#finding)
- [I want to find a string in any commit](#i-want-to-find-a-string-in-any-commit)
- [I want to find by author/committer](#i-want-to-find-by-authorcommitter)
- [I want to list commits containing specific files](#i-want-to-list-commits-containing-specific-files)
- [I want to view the commit history for a specific function](#i-want-to-view-the-commit-history-for-a-specific-function)
- [Find a tag where a commit is referenced](#find-a-tag-where-a-commit-is-referenced)
- [Submodules](#submodules)
- [Clone all submodules](#clone-all-submodules)
- [Remove a submodule](#remove-a-submodule)
- [Miscellaneous Objects](#miscellaneous-objects)
- [Copy a folder or file from one branch to another](#copy-a-folder-or-file-from-one-branch-to-another)
- [Restore a deleted file](#restore-a-deleted-file)
- [Delete tag](#delete-tag)
- [Recover a deleted tag](#recover-a-deleted-tag)
- [Deleted Patch](#deleted-patch)
- [Exporting a repository as a Zip file](#exporting-a-repository-as-a-zip-file)
- [Push a branch and a tag that have the same name](#push-a-branch-and-a-tag-that-have-the-same-name)
- [Tracking Files](#tracking-files)
- [I want to change a file name's capitalization, without changing the contents of the file](#i-want-to-change-a-file-names-capitalization-without-changing-the-contents-of-the-file)
- [I want to overwrite local files when doing a git pull](#i-want-to-overwrite-local-files-when-doing-a-git-pull)
- [I want to remove a file from Git but keep the file](#i-want-to-remove-a-file-from-git-but-keep-the-file)
- [I want to revert a file to a specific revision](#i-want-to-revert-a-file-to-a-specific-revision)
- [I want to list changes of a specific file between commits or branches](#i-want-to-list-changes-of-a-specific-file-between-commits-or-branches)
- [I want Git to ignore changes to a specific file](#i-want-git-to-ignore-changes-to-a-specific-file)
- [Debugging with Git](#debugging-with-git)
- [Configuration](#configuration)
- [I want to add aliases for some Git commands](#i-want-to-add-aliases-for-some-git-commands)
- [I want to add an empty directory to my repository](#i-want-to-add-an-empty-directory-to-my-repository)
- [I want to cache a username and password for a repository](#i-want-to-cache-a-username-and-password-for-a-repository)
- [I want to make Git ignore permissions and filemode changes](#i-want-to-make-git-ignore-permissions-and-filemode-changes)
- [I want to set a global user](#i-want-to-set-a-global-user)
- [I want to add command line coloring for Git](#i-want-to-add-command-line-coloring-for-git)
- [I've no idea what I did wrong](#ive-no-idea-what-i-did-wrong)
- [Git Shortcuts](#git-shortcuts)
- [Git Bash](#git-bash)
- [PowerShell on Windows](#powershell-on-windows)
- [Other Resources](#other-resources)
- [Books](#books)
- [Tutorials](#tutorials)
- [Scripts and Tools](#scripts-and-tools)
- [GUI Clients](#gui-clients)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
2020-02-13 11:04:44 +06:00
## リポジトリ
2020-02-13 09:13:04 +06:00
2020-02-24 15:12:18 +06:00
### ローカルリポジトリを初期設定したい
2020-02-13 09:13:04 +06:00
2020-02-24 15:12:18 +06:00
既存のディレクトリを Git リポジトリとして初期設定するには、次を実行します。
2020-02-13 09:13:04 +06:00
```sh
(my-folder) $ git init
```
2020-02-13 11:04:44 +06:00
### リモートリポジトリをクローンしたい
2020-02-13 09:13:04 +06:00
2020-02-24 15:12:18 +06:00
リモートリポジトリをクローン(コピー)したいときは、リポジトリの URL をコピーし、次を実行します。
2020-02-13 09:13:04 +06:00
```sh
$ git clone [url]
```
2020-02-13 11:04:44 +06:00
すると、リモートリポジトリと同名のフォルダにリポジトリの内容が保存されます。
2020-02-13 16:29:45 +06:00
リモートリポジトリのあるサーバに接続できる必要があります。大抵の場合インターネット接続があれば大丈夫です。
2020-02-13 09:13:04 +06:00
2020-02-24 15:12:18 +06:00
リモートリポジトリと異なる名前のフォルダにクローンしたいときは、次のようにします。
2020-02-13 09:13:04 +06:00
```sh
$ git clone [url] name-of-new-folder
```
2020-02-13 11:04:44 +06:00
### 間違ったリモートリポジトリを設定してしまった
2020-02-13 09:13:04 +06:00
2020-02-13 11:04:44 +06:00
問題はいくつかの場合に分けられます。
2020-02-13 09:13:04 +06:00
2020-02-13 16:29:45 +06:00
間違ったリポジトリをクローンしてしまったときは、`git clone` で作ったディレクトリを削除して、正しいリポジトリをクローンし直せばよいです。
2020-02-13 09:13:04 +06:00
2020-02-24 15:12:18 +06:00
間違ったリポジトリを既存のローカルリポジトリの origin に設定してしまったときは、次のように origin の URL を変更しましょう。
2020-02-13 09:13:04 +06:00
```sh
$ git remote set-url origin [url of the actual repo]
```
2020-02-24 15:12:18 +06:00
ほかの問題は[この StackOverflow トピック](https://stackoverflow.com/questions/2432764/how-to-change-the-uri-url-for-a-remote-git-repository#2432799)を参照してください。
2020-02-13 09:13:04 +06:00
2020-02-13 11:04:44 +06:00
### 他の人のリポジトリにコードを書き加えたい
2020-02-13 09:13:04 +06:00
2020-02-24 15:12:18 +06:00
Git では、アクセス権がないかぎり他の人のリポジトリに書き込むことはできません。
GitHub は Git リポジトリのホスティングサービスであって Git 自体とは異なるものですが、GitHub でもやはり同様です。
しかし、パッチでコードを提案することができます。
GitHub ならフォークとプルリクエストの機能がこれにあたります。
2020-02-13 09:13:04 +06:00
2020-02-24 15:12:18 +06:00
まずはフォークについて説明しましょう。
フォークはリポジトリのコピーです。
Git 自体の機能ではないものの、GitHub, BitBucket, GitLab やその他のホスティングサービスにはこの機能があり、各サービスの UI を通して実行できます。
2020-02-13 09:13:04 +06:00
2020-02-13 11:04:44 +06:00
#### プルリクエストでコードを提案するには
2020-02-13 09:13:04 +06:00
2020-02-24 15:12:18 +06:00
リポジトリをフォークしたら、ローカルマシンにクローンして編集しましょう。
ちょっとした編集なら GitHub 上でもできるでしょうが、この文書は GitHub フライトルールではないので、ローカルで編集する方法を説明します。
2020-02-13 09:13:04 +06:00
```sh
2020-02-13 11:04:44 +06:00
# ssh を使う場合
2020-02-13 09:13:04 +06:00
$ git clone git@github.com:k88hudson/git-flight-rules.git
2020-02-13 11:04:44 +06:00
# https を使う場合
2020-02-13 09:13:04 +06:00
$ git clone https://github.com/k88hudson/git-flight-rules.git
```
2020-02-24 15:12:18 +06:00
できたディレクトリに `cd` で移動し、`git remote` を実行してください。
リモートのリストが表示されるはずです。
2020-02-13 16:29:45 +06:00
ただ、おそらく表示されるのは `k88hudson/git-flight-rules` を参照する `origin` だけなので、自分がフォークして作った方のリモートも用意する必要があります。
2020-02-13 09:13:04 +06:00
2020-02-24 15:12:18 +06:00
Git では、自分自身のリポジトリのリモートは `origin`、フォークした元のリポジトリには `upstream` と名付けるのが一般的です。
これにならって、まず、リモート `origin` の名前を `upstream` に変更しましょう。
2020-02-13 09:13:04 +06:00
```sh
$ git remote rename origin upstream
```
2020-02-13 16:29:45 +06:00
実は `git remote set-url` でも同じことができますが、時間と手間が余計にかかります。
2020-02-13 09:13:04 +06:00
2020-02-13 11:04:44 +06:00
次に、自分のプロジェクトを参照する新しいリモートを作成します。
2020-02-13 09:13:04 +06:00
```sh
$ git remote add origin git@github.com:YourName/git-flight-rules.git
```
2020-02-24 15:12:18 +06:00
この時点でリモートは二つです。
2020-02-13 11:04:44 +06:00
2020-02-13 16:29:45 +06:00
- `origin` は自分のリポジトリを参照しています。
2020-02-13 11:04:44 +06:00
- `upstream` は元のリポジトリを参照しています。
2020-02-13 09:13:04 +06:00
2020-02-13 11:04:44 +06:00
`origin` は読み取り・書き込みの両方ができ、`upstream` は読み取り専用です。
2020-02-13 09:13:04 +06:00
2020-02-13 16:29:45 +06:00
編集が済んだら、編集内容を(通常はブランチ内から)リモート `origin` にプッシュしましょう。
2020-02-24 15:12:18 +06:00
ブランチ内にいる場合、次のように `--set-upstream` を使うと、次回から同じブランチからプッシュする際にリモートを指定せずに済みます。
2020-02-13 09:13:04 +06:00
```sh
$ (feature/my-feature) git push --set-upstream origin feature/my-feature
```
2020-02-13 16:29:45 +06:00
Git で CLI からプルリクエストを送る方法はありません([hub](http://github.com/github/hub) のようなツールを使えば別ですが)。
2020-02-24 15:12:18 +06:00
プルリクエストを送りたいときは、GitHubあるいは他のホスティングサービス上でプルリクエストを作成してください。
元のリポジトリとフォークしたリポジトリの紐付けはホスティングサービスが自動的にしてくれます。
2020-02-13 11:04:44 +06:00
プルリクエストの後、コードレビューのフィードバックに対応するのを忘れないようにしましょう。
2020-02-13 09:13:04 +06:00
2020-02-13 11:04:44 +06:00
#### フォークしたリポジトリを、元のリポジトリの最新版に合わせて更新したい
2020-02-13 09:13:04 +06:00
2020-02-13 11:04:44 +06:00
そのうち `upstream` リポジトリが更新され、自分の `origin` にプルしたくなるかもしれません。
2020-02-13 16:29:45 +06:00
自分だけでなく他の人も共同作業していることを忘れないようにしてください。
自分のフィーチャーブランチにいて、これを元のリポジトリに合わせて更新したい場合を想定します。
2020-02-13 09:13:04 +06:00
2020-02-24 15:12:18 +06:00
元のプロジェクトを参照するリモートは設定してありますか? まだなら今やってしまいましょう。
通常はリモートの名前に `upstream` を使います。
2020-02-13 09:13:04 +06:00
```sh
$ (master) git remote add upstream <link-to-original-repository>
# $ (master) git remote add upstream git@github.com:k88hudson/git-flight-rules.git
```
2020-02-24 15:12:18 +06:00
これで `upstream` から最新版を取得できるようになりました。
2020-02-13 09:13:04 +06:00
```sh
$ (master) git fetch upstream
$ (master) git merge upstream/master
2020-02-13 16:29:45 +06:00
# コマンド一つでもできる
2020-02-13 09:13:04 +06:00
$ (master) git pull upstream master
```
2020-02-13 20:52:53 +06:00
## コミットの編集
2020-02-13 09:13:04 +06:00
<a name="diff-last"></a>
2020-02-13 20:52:53 +06:00
### 何をコミットしたかわからなくなった
2020-02-13 09:13:04 +06:00
2020-02-13 20:52:53 +06:00
何も考えず `git commit -a` で編集をコミットしてしまい、その内容がわからないとします。
2020-02-24 15:50:49 +06:00
現在の HEAD の最新のコミット内容は次のように表示できます。
2020-02-13 09:13:04 +06:00
```sh
(master)$ git show
```
2020-02-24 15:50:49 +06:00
もしくは次の通りです。
2020-02-13 09:13:04 +06:00
```sh
$ git log -n1 -p
```
2020-02-24 15:50:49 +06:00
特定のコミットの時点のファイルの中身を見たいときは次のようにします(`<commitid>` は見たいコミット)。
2020-02-13 09:13:04 +06:00
```sh
$ git show <commitid>:filename
```
2020-02-13 20:52:53 +06:00
### コミットメッセージに間違った内容を書いてしまった
2020-02-13 09:13:04 +06:00
2020-02-13 20:52:53 +06:00
コミットメッセージに間違った内容を書いてしまったとします。
2020-02-24 15:50:49 +06:00
コミットがまだプッシュされていない場合は、次のようにして編集内容は変えずにコミットメッセージを編集できます。
2020-02-13 09:13:04 +06:00
```sh
$ git commit --amend --only
```
2020-02-24 15:50:49 +06:00
デフォルトのテキストエディタが開き、コミットメッセージを編集できます。
次のようにして、一つのコマンドでいっぺんにやることもできます。
2020-02-13 09:13:04 +06:00
```sh
$ git commit --amend --only -m 'xxxxxxx'
```
2020-02-13 20:52:53 +06:00
既にコミットをプッシュしてしまった場合、コミットを修正して強制プッシュすることはできますが、おすすめしません。
2020-02-13 09:13:04 +06:00
<a name="commit-wrong-author"></a>
2020-02-24 15:50:49 +06:00
### 間違った名前・メールアドレスでコミットしてしまった
2020-02-13 09:13:04 +06:00
2020-02-13 20:52:53 +06:00
コミットが一つだけなら、次のように修正します。
2020-02-13 09:13:04 +06:00
```sh
$ git commit --amend --no-edit --author "New Authorname <authoremail@mydomain.com>"
```
2020-02-24 15:50:49 +06:00
あるいは、名前とメールアドレスを `git config --global author.(name|email)` で正しく設定してから、次を実行します。
2020-02-13 09:13:04 +06:00
```sh
$ git commit --amend --reset-author --no-edit
```
2020-02-13 20:52:53 +06:00
履歴すべてについて変更したい場合は、`git filter-branch` の man ページを参照してください。
2020-02-13 09:13:04 +06:00
2020-02-13 20:52:53 +06:00
### 直前のコミットからファイルを削除したい
2020-02-13 09:13:04 +06:00
2020-02-24 15:50:49 +06:00
直前のコミットから特定のファイルに関する編集内容を削除するには次のようにします。
2020-02-13 09:13:04 +06:00
```sh
$ git checkout HEAD^ myfile
$ git add myfile
$ git commit --amend --no-edit
```
2020-02-13 20:52:53 +06:00
直前のコミットで新たに追加したファイルをGit のみから)削除したいときは次の通りです。
2020-02-13 09:13:04 +06:00
```sh
$ git rm --cached myfile
$ git commit --amend --no-edit
```
2020-02-24 15:50:49 +06:00
このコマンドは、不要なファイルをパッチにコミットしてしまい、強制プッシュでリモートのパッチを更新したいときに特に便利です。
オプション `--no-edit` は既存のコミットメッセージを変更しないようにするためのものです。
2020-02-13 09:13:04 +06:00
<a name="delete-pushed-commit"></a>
2020-02-13 20:52:53 +06:00
### 直前のコミットを削除したい
2020-02-13 09:13:04 +06:00
2020-02-13 20:52:53 +06:00
既にプッシュしたコミットを削除するには次のようにします。
ただし、編集履歴が不可逆的に変更され、リポジトリから変更内容をプルしてしまった他の人の編集履歴は滅茶苦茶になります。
要するに、よくわからない場合は絶対にしないでください。
2020-02-13 09:13:04 +06:00
```sh
$ git reset HEAD^ --hard
$ git push --force-with-lease [remote] [branch]
```
2020-02-13 20:52:53 +06:00
まだコミットをプッシュしていない場合は、次のようにして(ステージされた編集はそのままで)直前のコミットをする前の状態に Git をリセットできます。
2020-02-13 09:13:04 +06:00
```
(my-branch*)$ git reset --soft HEAD@{1}
```
2020-02-13 20:52:53 +06:00
これはプッシュしていない場合にのみ有効な方法です。
プッシュしてしまった場合、本当に安全な方法は `git revert SHAofBadCommit` だけです。
2020-02-24 15:50:49 +06:00
このコマンドは、直前のコミットを相殺するようなコミットを新たに作成します。
プッシュしたブランチがリベースについて安全である場合(つまり、他の開発者がプルすることを想定していない場合)は、`git push --force-with-lease` を使っても大丈夫です。
<!--For more, see [the above section](#deleteremove-last-pushed-commit).-->
2020-02-13 09:13:04 +06:00
<a name="delete-any-commit"></a>
2020-02-13 20:52:53 +06:00
### 任意のコミットを削除したい
2020-02-13 09:13:04 +06:00
2020-02-24 15:50:49 +06:00
上と同様に、やむを得ない場合以外絶対に行わないでください。
2020-02-13 09:13:04 +06:00
```sh
$ git rebase --onto SHA1_OF_BAD_COMMIT^ SHA1_OF_BAD_COMMIT
$ git push --force-with-lease [remote] [branch]
```
2020-02-24 15:50:49 +06:00
あるいは、[対話的 rebase](#interactive-rebase) で削除したいコミットに対応する行を選択して削除します。
2020-02-13 09:13:04 +06:00
<a name="#force-push"></a>
2020-02-13 20:52:53 +06:00
### 修正したコミットをリモートにプッシュしようとしたら、エラーメッセージが出た
2020-02-13 09:13:04 +06:00
```sh
To https://github.com/yourusername/repo.git
! [rejected] mybranch -> mybranch (non-fast-forward)
error: failed to push some refs to 'https://github.com/tanay1337/webmaker.org.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
```
2020-02-24 15:50:49 +06:00
amend による修正は、rebase と同様に(後述)、**古いコミットを新たなコミットで置き換えます**。
それゆえ、修正前のコミットを既にリモートにプッシュしてしまった場合は、強制プッシュ (`--force-with-lease`) しなければいけません。
強制プッシュには細心の注意が必要です。
*必ず*ブランチを指定するように!
2020-02-13 09:13:04 +06:00
```sh
(my-branch)$ git push origin mybranch --force-with-lease
```
2020-02-24 15:50:49 +06:00
一般論として、**強制プッシュは避けましょう**。
修正したコミットを強制プッシュするよりは、新たなコミットを作ってプッシュするのがベストです。
強制プッシュは、対象のブランチやその子ブランチで作業した他の開発者のソース履歴にコンフリクトをきたします。
誰かが同じブランチで作業していて、強制プッシュがその人の編集を上書きしてしまう場合は、`--force-with-lease` も失敗します。
2020-02-13 09:13:04 +06:00
2020-02-24 15:50:49 +06:00
他の誰も同じブランチで作業していないことが*絶対に*確実な場合、あるいはブランチの一部を*無条件で*更新したい場合は `--force` (`-f`) で行うことができますが、これは原則として避けるべきです。
2020-02-13 09:13:04 +06:00
<a href="undo-git-reset-hard"></a>
2020-02-13 20:52:53 +06:00
### 間違えて hard reset してしまい、元に戻したい
2020-02-13 09:13:04 +06:00
2020-02-24 15:50:49 +06:00
間違えて `git reset --hard` をしてしまっても、大抵はコミットを復元できます。
Git は数日間のログを全て残してくれているからです。
2020-02-13 09:13:04 +06:00
2020-02-24 15:50:49 +06:00
注意:これは作業がバックアップされている場合、つまりコミットないしスタッシュされている場合に限ります。
`git reset --hard` はコミットされていない変更を*削除*してしまうので、注意して使ってください。
(安全なのは `git reset --keep` を使うことです。)
2020-02-13 09:13:04 +06:00
```sh
(master)$ git reflog
```
2020-02-24 15:50:49 +06:00
過去のコミットとリセットに対応するコミットが表示されるので、復元したいコミットの SHA を選んでリセットします。
2020-02-13 09:13:04 +06:00
```sh
(master)$ git reset --hard SHA1234
```
2020-02-13 20:52:53 +06:00
これで大丈夫です。
2020-02-13 09:13:04 +06:00
<a href="undo-a-commit-merge"></a>
2020-02-13 20:52:53 +06:00
### 間違えてマージをコミットしてプッシュしてしまった
2020-02-24 15:50:49 +06:00
マージの準備ができていないフィーチャーブランチをメインのブランチにマージしてしまったときは、マージを取り消すことができます。
ただし注意すべき点は、マージコミットには複数(通常は二つ)の親があることです。
2020-02-13 09:13:04 +06:00
2020-02-13 20:52:53 +06:00
次のコマンドを実行します。
2020-02-13 09:13:04 +06:00
```sh
(feature-branch)$ git revert -m 1 <commit>
```
2020-02-24 15:50:49 +06:00
ここでオプション `-m 1` は差し戻す先の親として親 1マージした先のブランチを指定します。
2020-02-13 20:52:53 +06:00
2020-02-24 15:50:49 +06:00
注意:親の番号はコミット ID とは異なります。
マージコミットの行は `Merge: 8e2ce2d 86ac2e7` のようになっています。
親番号はこのコミットの親を指定する 1 から始まる番号で、最初の番号は 1 番、次は 2 番、のように振られます。
2020-02-13 09:13:04 +06:00
<a href="undo-sensitive-commit-push"></a>
2020-02-13 20:52:53 +06:00
### 間違えて機密情報を含むファイルをコミットしプッシュしてしまった
2020-02-13 09:13:04 +06:00
2020-02-24 15:50:49 +06:00
機密情報やプライベートな情報(パスワードやキー等)を含むデータを誤ってプッシュしてしまった場合、コミットを修正できます。
ただし、ひとたびデータをコミットしてプッシュしてしまったら、その内容は盗み取られるおそれがあることに留意してください。
下の手順で公開リポジトリやローカルからデータを削除できますが、他の誰かが既にプルしたデータを削除することは**不可能です**。
パスワードをコミットしてしまった場合は**直ちに変更してください**。
キーをコミットしてしまった場合は**直ちに再生成しましょう**。
2020-02-13 20:52:53 +06:00
誰かが既に機密情報をプルしてしまった可能性がある限り、プッシュしたコミットを修正するだけでは不十分です。
2020-02-13 09:13:04 +06:00
2020-02-13 20:52:53 +06:00
ファイルを編集して機密情報を削除したあと、次を実行します。
2020-02-24 15:50:49 +06:00
2020-02-13 09:13:04 +06:00
```sh
(feature-branch)$ git add edited_file
(feature-branch)$ git commit --amend --no-edit
(feature-branch)$ git push --force-with-lease origin [branch]
```
2020-02-13 20:52:53 +06:00
ファイルごと削除したいがローカルには残しておきたい場合、次を実行します。
2020-02-24 15:50:49 +06:00
2020-02-13 09:13:04 +06:00
```sh
(feature-branch)$ git rm --cached sensitive_file
echo sensitive_file >> .gitignore
(feature-branch)$ git add .gitignore
(feature-branch)$ git commit --amend --no-edit
(feature-branch)$ git push --force-with-lease origin [branch]
```
2020-02-24 15:50:49 +06:00
2020-02-13 20:52:53 +06:00
あるいは、機密情報をローカルの環境変数に保存しておきましょう。
2020-02-13 09:13:04 +06:00
2020-02-13 20:52:53 +06:00
ファイルごと削除した上でローカルからも削除したい場合は、次を実行します。
2020-02-24 15:50:49 +06:00
2020-02-13 09:13:04 +06:00
```sh
(feature-branch)$ git rm sensitive_file
(feature-branch)$ git commit --amend --no-edit
(feature-branch)$ git push --force-with-lease origin [branch]
```
2020-02-24 15:50:49 +06:00
既に他のコミットをしてしまった場合(つまり、機密情報のコミットが直前のコミットよりも前である場合)は、リベースする必要があります。
2020-02-13 09:13:04 +06:00
<a href="#i-want-to-remove-a-large-file-from-ever-existing-in-repo-history"></a>
2020-02-13 20:52:53 +06:00
### 大容量のファイルに関する履歴を完全に削除したい
削除したいファイルが機密情報である場合は[機密情報を削除する方法](#i-accidentally-committed-and-pushed-files-containing-sensitive-data)を参照してください。
2020-02-13 09:13:04 +06:00
2020-02-24 15:50:49 +06:00
コミットで大容量のファイルや不要なファイルを削除しても、`.git` フォルダの Git 履歴には残るので、`git clone` したときに余計なファイルまでダウンロードしてしまうことになります。
2020-02-13 09:13:04 +06:00
2020-02-24 15:50:49 +06:00
ここで説明する手順には強制プッシュを必要とし、リポジトリ履歴を大きく変更してしまいます。
誰かがリモートで共同作業している場合は、全員のローカルの編集履歴がプッシュされていることを確認しておいてください。
2020-02-13 20:52:53 +06:00
2020-02-24 15:50:49 +06:00
履歴を書き換えるには二つの方法があります。
ビルトインの `git-filter-branch` と [`bfg-repo-cleaner`](https://rtyley.github.io/bfg-repo-cleaner/) です。
2020-02-13 20:52:53 +06:00
`bfg` はエレガントで性能がよい一方、サードパーティ製のソフトをダウンロードしなければならず、Java も必要です。
2020-02-24 15:50:49 +06:00
ここでは両方を説明します。
最後のステップでは強制プッシュをしますが、リポジトリの履歴の大部分を永久に変更するため、通常の強制プッシュよりもなお特別な配慮が必要になります。
2020-02-13 20:52:53 +06:00
#### おすすめの方法:サードパーティ製の bfg を使う
2020-02-13 09:13:04 +06:00
2020-02-24 15:50:49 +06:00
bfg-repo-cleaner を使うには Java が必要です。
[ここ](https://rtyley.github.io/bfg-repo-cleaner/)から bfg の jar ファイルをダウンロードしてください。
下の例では `bfg.jar` を使いますが、ダウンロードしたものには `bfg-1.13.0.jar` のようにバージョン番号がついているかもしれません。
2020-02-13 09:13:04 +06:00
2020-02-13 20:52:53 +06:00
特定のファイルを削除する場合は次のようにします。
2020-02-24 15:50:49 +06:00
2020-02-13 09:13:04 +06:00
```sh
(master)$ git rm path/to/filetoremove
(master)$ git commit -m "Commit removing filetoremove"
(master)$ java -jar ~/Downloads/bfg.jar --delete-files filetoremove
```
2020-02-24 15:50:49 +06:00
なお、bfg を使うときは、ファイルがサブディレクトリにあってもそのままのファイル名を入力することに注意してください。
パターンからファイルを削除することもできます。例えば次の通りです。
2020-02-13 09:13:04 +06:00
```sh
(master)$ git rm *.jpg
(master)$ git commit -m "Commit removing *.jpg"
(master)$ java -jar ~/Downloads/bfg.jar --delete-files *.jpg
```
2020-02-24 15:50:49 +06:00
bfg は最新のコミットにあるファイルには影響しません。
例えば、リポジトリに複数あった大容量の .tga ファイルのうち一部を以前のコミットで削除したとして、bfg を実行しても最新のコミットにあるファイルはそのままです。
2020-02-13 09:13:04 +06:00
2020-02-24 15:50:49 +06:00
なお、コミットでファイル名を変更した場合、例えばもともと `LargeFileFirstName.mp4` だったファイルが後のコミットで `LargeFileSecondName.mp4` に変更されている場合は、`java -jar ~/Downloads/bfg.jar --delete-files LargeFileSecondName.mp4` を実行しても Git の履歴からは削除されません。
両方のファイル名それぞれについて `--delete-files` を実行するか、パターンマッチで両方削除してください。
2020-02-13 09:13:04 +06:00
2020-02-13 20:52:53 +06:00
#### ビルトインの方法git-filter-branch を使う
2020-02-13 09:13:04 +06:00
2020-02-13 20:52:53 +06:00
`git-filter-branch` はややこしくて機能も貧弱ですが、`bfg` のインストールや実行ができなくても使えます。
2020-02-13 09:13:04 +06:00
2020-02-24 15:50:49 +06:00
以下では、`filepattern` を名前やパターン(`*.jpg` など)に置き換えてください。
パターンにマッチしたファイルの履歴が全ての履歴とブランチから削除されます。
2020-02-13 09:13:04 +06:00
```sh
(master)$ git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch filepattern' --prune-empty --tag-name-filter cat -- --all
```
2020-02-24 15:50:49 +06:00
ここで使っている `--tag-name-filter cat` は煩雑ですが、このように `cat` を使うのが元のタグを新しいコミットにつける最も簡単な方法です。
また、`--prune-empty` は現在空のコミットを全て削除します。
2020-02-13 09:13:04 +06:00
2020-02-13 20:52:53 +06:00
#### 最後のステップ: 変更した履歴をプッシュする
2020-02-24 15:50:49 +06:00
ファイルを削除したら、リポジトリのものを壊していないか慎重に確認してください。
2020-02-13 20:52:53 +06:00
何か壊してしまった場合は、リポジトリを再度クローンしてやり直すのが最も簡単です。
最後のステップとして、必要に応じて Git ガベージコレクションで .git フォルダの容量を最小化してから、強制プッシュします。
2020-02-13 09:13:04 +06:00
```sh
(master)$ git reflog expire --expire=now --all && git gc --prune=now --aggressive
(master)$ git push origin --force --tags
```
2020-02-24 15:50:49 +06:00
リポジトリの履歴を全て書き換えているので、`git push` の量が膨大すぎて `“The remote end hung up unexpectedly”` というエラーが返るかもしれません。
その場合は Git の post buffer を増やしてみます。
2020-02-13 20:52:53 +06:00
2020-02-13 09:13:04 +06:00
```sh
(master)$ git config http.postBuffer 524288000
(master)$ git push --force
```
2020-02-13 20:52:53 +06:00
うまくいかない場合は、コミットを手作業で小分けにしてプッシュします。
プッシュが成功するまで、`<number>` を増やしながら次のコマンドを試してください。
2020-02-13 09:13:04 +06:00
```sh
(master)$ git push -u origin HEAD~<number>:refs/head/master --force
```
2020-02-24 15:50:49 +06:00
プッシュが成功したら、通常の`git push` が 成功するまで `<number>` を徐々に減らしてください。
2020-02-13 09:13:04 +06:00
<a href="i-need-to-change-the-content-of-a-commit-which-is-not-my-last"></a>
2020-02-13 20:52:53 +06:00
### 直近でないコミットの内容を編集したい
複数(たとえば三件)のコミットを行ったあと、文脈的に最初のコミットに属する作業をし忘れたことに気づいたとします。
この作業を新たなコミットとして行えばコードベースは綺麗に保てるものの、コミットがアトミックでなくなってしまう(同じ文脈の作業が同じコミットに属さない)ので、この状況は厄介です。
2020-02-24 15:50:49 +06:00
し忘れた作業が属するべきコミットを編集して作業を取り入れつつ、その後のコミットには手をつけないようにしたいとき、`git rebase` が役に立ちます。
2020-02-13 09:13:04 +06:00
2020-02-13 20:52:53 +06:00
最後から三件目のコミットを編集したいとします。
2020-02-13 09:13:04 +06:00
```sh
(your-branch)$ git rebase -i HEAD~4
```
2020-02-13 20:52:53 +06:00
上のコマンドで対話的リベースモードに入り、直近三件のコミットを編集できるようになります。
テキストエディタが開き、次のような内容が表示されます。
2020-02-13 09:13:04 +06:00
```sh
pick 9e1d264 The third last commit
pick 4b6e19a The second to last commit
pick f4037ec The last commit
```
2020-02-13 20:52:53 +06:00
これを次のように編集します。
2020-02-13 09:13:04 +06:00
```sh
edit 9e1d264 The third last commit
pick 4b6e19a The second to last commit
pick f4037ec The last commit
```
2020-02-24 15:50:49 +06:00
これは最後から三件目のコミットを編集しつつ、他の二件はそのままにするよう `rebase` に指示するコマンドです。
2020-02-13 20:52:53 +06:00
テキストエディタを保存して終了したら、Git がリベースを始めます。指定したコミットで止まり、そのコミットを編集できるようになります。
これで最初にコミットしたときにし忘れた作業を適用できます。編集とステージによって適用しましょう。
その後、次を実行します。
2020-02-13 09:13:04 +06:00
```sh
(your-branch)$ git commit --amend
```
2020-02-24 15:50:49 +06:00
これはコミットメッセージはそのままでコミットを作り直すよう Git に指示するコマンドです。
2020-02-13 20:52:53 +06:00
これで面倒な作業は終わりです。
2020-02-13 09:13:04 +06:00
```sh
(your-branch)$ git rebase --continue
```
2020-02-13 20:52:53 +06:00
あとは上を実行すれば完了です。
2020-02-24 15:55:52 +06:00
## ステージ
2020-02-13 09:13:04 +06:00
<a href="#i-want-to-stage-all-tracked-files-and-leave-untracked-files"></a>
2020-02-14 18:35:05 +06:00
### バージョン管理されているファイルを全部ステージしたい
2020-02-13 09:13:04 +06:00
```sh
$ git add -u
```
2020-02-14 18:35:05 +06:00
#### バージョン管理されているファイルの一部をステージするには
2020-02-13 09:13:04 +06:00
```sh
2020-02-14 18:35:05 +06:00
# 拡張子が .txt のファイルをステージする
2020-02-13 09:13:04 +06:00
$ git add -u *.txt
2020-02-14 18:35:05 +06:00
# src ディレクトリ内の全ファイルをステージする
2020-02-13 09:13:04 +06:00
$ git add -u src/
```
<a href="#i-need-to-add-staged-changes-to-the-previous-commit"></a>
2020-02-14 18:35:05 +06:00
### ステージされた編集内容を直前のコミットに追加したい
2020-02-13 09:13:04 +06:00
```sh
(my-branch*)$ git commit --amend
```
2020-02-24 15:55:52 +06:00
コミットメッセージを変更したくないときは、コミットメッセージを再利用するよう Git に指示します。
2020-02-13 09:13:04 +06:00
```sh
(my-branch*)$ git commit --amend -C HEAD
```
<a name="commit-partial-new-file"></a>
2020-02-14 18:35:05 +06:00
### 新しいファイルの全部ではなく一部をステージしたい
2020-02-13 09:13:04 +06:00
2020-02-24 15:55:52 +06:00
通常、ファイルの一部をステージするには次を実行します。
2020-02-13 09:13:04 +06:00
```sh
$ git add --patch filename.x
```
2020-02-14 18:35:05 +06:00
短縮形は `-p` です。これにより対話モードが開きます。
オプション `s` をつけるとコミットを分割 (split) できます。ただし、新しく作ったファイルの場合このオプションは使えません。
2020-02-24 15:55:52 +06:00
ファイルを新たに追加するには、次を実行します。
2020-02-13 09:13:04 +06:00
```sh
$ git add -N filename.x
```
2020-02-14 18:35:05 +06:00
オプション `e` を使うと、どの行を追加するか手動で選択することができます。
2020-02-24 15:55:52 +06:00
コマンド `git diff --cached` あるいは `git diff --staged` を実行すると、ステージした行がローカルに保存されたものと比較して表示されます。
2020-02-13 09:13:04 +06:00
<a href="stage-in-two-commits"></a>
2020-02-14 18:35:05 +06:00
### 一つのファイルに加えた編集を二つの異なるコミットに追加したい
2020-02-13 09:13:04 +06:00
2020-02-24 15:55:52 +06:00
コマンド `git add` はファイル全体をコミットに追加します。
また、`git add -p` を使うと、どの編集内容を追加するか対話的に選択できます。
2020-02-13 09:13:04 +06:00
<a href="selective-unstage-edits"></a>
2020-02-14 18:35:05 +06:00
### ステージした編集内容が多すぎるので、いくつかのコミットに分割したい
2020-02-13 09:13:04 +06:00
2020-02-24 15:55:52 +06:00
コマンド `git reset -p` を実行すると、パッチモードのリセットダイアログが開きます。
なお、`git add -p` と似ていますが、"yes" がステージを取り消して次のコミットから除去することを意味する点で異なります。
2020-02-13 09:13:04 +06:00
<a href="unstaging-edits-and-staging-the-unstaged"></a>
2020-02-14 18:35:05 +06:00
### ステージされていない編集内容をステージし、ステージされた編集内容のステージを取り消したい
2020-02-13 09:13:04 +06:00
2020-02-14 18:35:05 +06:00
通常は、ステージされたファイルのステージングを一旦全部取り消したあと、コミットしたいものをピックするべきです。
2020-02-24 15:55:52 +06:00
ステージされている編集とされていない編集を切り替えたいときは、ステージされた編集を記録しておく仮のコミットを作成し、ステージされていないファイルをステージしてスタッシュします。
それから仮のコミットをリセットして、スタッシュを pop します。
2020-02-13 09:13:04 +06:00
```sh
$ git commit -m "WIP"
2020-02-14 18:35:05 +06:00
$ git add . # バージョン管理されていないファイルも追加される
2020-02-13 09:13:04 +06:00
$ git stash
$ git reset HEAD^
$ git stash pop --index 0
```
2020-02-24 15:55:52 +06:00
注意 1ここで `pop` を使うのは、操作を複数回行ってもなるべく結果が変わらないようにするためです。
2020-02-14 18:35:05 +06:00
注意 2ここで `--index` を指定しないと、ステージされたファイルはステージされていない扱いになります(理由は[このリンク](https://stackoverflow.com/questions/31595873/git-stash-with-staged-files-does-stash-convert-staged-files-to-unstaged?answertab=active#tab-top)を参照してください)。
2020-02-13 09:13:04 +06:00
2020-02-14 19:04:42 +06:00
## ステージされていない編集
2020-02-13 09:13:04 +06:00
<a href="move-unstaged-edits-to-new-branch"></a>
2020-02-24 16:02:56 +06:00
### ステージされていない編集を新しいブランチに移したい
2020-02-13 09:13:04 +06:00
```sh
$ git checkout -b my-branch
```
<a href="move-unstaged-edits-to-old-branch"></a>
2020-02-24 16:02:56 +06:00
### ステージされていない編集を別の既存のブランチに移したい
2020-02-13 09:13:04 +06:00
```sh
$ git stash
$ git checkout my-branch
$ git stash pop
```
<a href="i-want-to-discard-my-local-uncommitted-changes"></a>
2020-02-24 16:02:56 +06:00
### コミットされていないローカルの編集を破棄したい
2020-02-13 09:13:04 +06:00
2020-02-24 16:02:56 +06:00
ステージされている編集とされていない編集の両方を全て破棄したいときは、次のようにします。
2020-02-13 09:13:04 +06:00
```sh
(my-branch)$ git reset --hard
2020-02-14 19:04:42 +06:00
# または
2020-02-13 09:13:04 +06:00
(master)$ git checkout -f
```
2020-02-24 16:02:56 +06:00
次のコマンドは `git add` でステージした全ファイルのステージを取り消します。
2020-02-13 09:13:04 +06:00
```sh
$ git reset
```
2020-02-24 16:02:56 +06:00
次のコマンドはコミットされていないローカルの編集を全て差し戻します(リポジトリのルートで実行する必要があります)。
2020-02-13 09:13:04 +06:00
```sh
$ git checkout .
```
2020-02-24 16:02:56 +06:00
特定のファイルやディレクトリについて、コミットされていない編集を差し戻すこともできます。
2020-02-13 09:13:04 +06:00
```sh
$ git checkout [some_dir|file.txt]
```
2020-02-24 16:02:56 +06:00
コミットされていない編集を全て差し戻すのには次の方法もあります(コマンドが長いですが、任意のサブディレクトリから実行できます)。
2020-02-13 09:13:04 +06:00
```sh
$ git reset --hard HEAD
```
2020-02-24 16:02:56 +06:00
次を実行するとローカルのバージョン管理されていないファイルが全て削除されます。
つまり、Git で管理されているファイルだけ残ります。
2020-02-13 09:13:04 +06:00
```sh
$ git clean -fd
```
2020-02-14 19:04:42 +06:00
Git に無視されるファイルも全て取り除くには `-x` を指定します。
2020-02-13 09:13:04 +06:00
2020-02-24 16:02:56 +06:00
### ステージされていない特定の編集を破棄したい
2020-02-13 09:13:04 +06:00
2020-02-24 16:02:56 +06:00
ワークツリーの編集の全部ではなく一部だけを破棄したい場合です。
2020-02-13 09:13:04 +06:00
2020-02-24 16:02:56 +06:00
残したい編集だけを残し、残したくない編集をチェックアウトします。
2020-02-13 09:13:04 +06:00
```sh
$ git checkout -p
2020-02-14 19:04:42 +06:00
# 破棄したいコードすべてについて y と答える
2020-02-13 09:13:04 +06:00
```
2020-02-24 16:02:56 +06:00
もう一つの方法は `stash` を使います。残したい編集をスタッシュし、ワークツリーをリセットして、残したい編集を適用します。
2020-02-13 09:13:04 +06:00
```sh
$ git stash -p
2020-02-14 19:04:42 +06:00
# 残したいコードを全て選ぶ
2020-02-13 09:13:04 +06:00
$ git reset --hard
$ git stash pop
```
2020-02-24 16:02:56 +06:00
あるいは、残したくない編集をスタッシュして、スタッシュを破棄してもよいです。
2020-02-13 09:13:04 +06:00
```sh
$ git stash -p
2020-02-14 19:04:42 +06:00
# 残したくないコードを全て選ぶ
2020-02-13 09:13:04 +06:00
$ git stash drop
```
2020-02-14 19:04:42 +06:00
### ステージされていない特定のファイルを破棄したい
2020-02-13 09:13:04 +06:00
2020-02-14 19:04:42 +06:00
ワークツリーの特定のファイル一つを取り除きたいときです。
2020-02-13 09:13:04 +06:00
```sh
$ git checkout myFile
```
2020-02-24 16:02:56 +06:00
ワークツリー上の複数のファイルを破棄したいときは、破棄したいファイルを列挙します。
2020-02-13 09:13:04 +06:00
```sh
$ git checkout myFirstFile mySecondFile
```
2020-02-24 16:02:56 +06:00
### ステージされていないローカルな編集だけを破棄したい
2020-02-13 09:13:04 +06:00
2020-02-24 16:02:56 +06:00
コミットもステージもされていないローカルの編集を全て破棄したいときは、次を実行します。
2020-02-13 09:13:04 +06:00
```sh
$ git checkout .
```
2020-02-14 19:04:42 +06:00
2020-02-13 09:13:04 +06:00
<a href="i-want-to-discard-all-my-untracked-files"></a>
2020-02-14 19:04:42 +06:00
### バージョン管理されていないファイルを全て破棄したい
2020-02-13 09:13:04 +06:00
2020-02-14 19:04:42 +06:00
バージョン管理されていないファイルを全て破棄したいときは、次を実行します。
2020-02-13 09:13:04 +06:00
```sh
$ git clean -f
```
<a href="I-want-to-unstage-specific-staged-file"></a>
2020-02-14 19:04:42 +06:00
### 特定のステージされたファイルのステージングを取り消したい
2020-02-13 09:13:04 +06:00
2020-02-24 16:02:56 +06:00
間違えてステージしたが、コミットはしていないファイルが一つまたは複数ある場合です。
そのステージを取り消すには次のようにします。
2020-02-13 09:13:04 +06:00
```sh
$ git reset -- <filename>
```
2020-02-14 19:04:42 +06:00
ファイルのステージングが取り消され、バージョン管理されていないものとみなされます。
2020-02-13 09:13:04 +06:00
2020-02-15 08:02:54 +06:00
## ブランチ
2020-02-13 09:13:04 +06:00
2020-02-15 08:02:54 +06:00
### 全ブランチの一覧を表示したい
2020-02-13 09:13:04 +06:00
2020-02-24 16:36:17 +06:00
ローカルブランチの一覧を表示
2020-02-13 09:13:04 +06:00
```sh
$ git branch
```
2020-02-24 16:36:17 +06:00
リモートブランチの一覧を表示
2020-02-13 09:13:04 +06:00
```sh
$ git branch -r
```
2020-02-24 16:36:17 +06:00
ローカルとリモート両方のブランチの一覧を表示
2020-02-13 09:13:04 +06:00
```sh
$ git branch -a
```
<a name="create-branch-from-commit"></a>
2020-02-15 08:02:54 +06:00
### コミットからブランチを作成する
2020-02-13 09:13:04 +06:00
```sh
$ git checkout -b <branch> <SHA1_OF_COMMIT>
```
<a name="pull-wrong-branch"></a>
2020-02-15 08:02:54 +06:00
### 間違ったブランチから、あるいは間違ったブランチにプルしてしまった
2020-02-13 09:13:04 +06:00
2020-02-24 16:36:17 +06:00
これも `git reflog` を使う場面です。
間違ったプルの前に HEAD が参照していたものを表示します。
2020-02-13 09:13:04 +06:00
```sh
(master)$ git reflog
ab7555f HEAD@{0}: pull origin wrong-branch: Fast-forward
c5bc55a HEAD@{1}: checkout: checkout message goes here
```
2020-02-24 16:36:17 +06:00
ブランチを適切なコミットにリセットするだけです。
2020-02-13 09:13:04 +06:00
```sh
$ git reset --hard c5bc55a
```
2020-02-15 08:02:54 +06:00
これで完了です。
2020-02-13 09:13:04 +06:00
<a href="discard-local-commits"></a>
2020-02-24 16:36:17 +06:00
### ローカルのコミットを破棄して、ブランチをサーバ上と同じ状態にしたい
2020-02-13 09:13:04 +06:00
2020-02-24 16:36:17 +06:00
サーバに編集をプッシュしていないことを確認してください。
2020-02-13 09:13:04 +06:00
2020-02-24 16:36:17 +06:00
コマンド `git status` を実行すると、自分が origin に対して何コミット分作業を進めたのか表示されます。
2020-02-13 09:13:04 +06:00
```sh
(my-branch)$ git status
# On branch my-branch
# Your branch is ahead of 'origin/my-branch' by 2 commits.
# (use "git push" to publish your local commits)
#
```
2020-02-24 16:36:17 +06:00
origin と同じ状態にリセットする(リモートと同じ状態にする)方法の一つは次の通りです。
2020-02-13 09:13:04 +06:00
```sh
(master)$ git reset --hard origin/my-branch
```
<a name="commit-wrong-branch"></a>
2020-02-15 08:02:54 +06:00
### 新しいブランチではなくマスターブランチにコミットしてしまった
2020-02-13 09:13:04 +06:00
2020-02-24 16:36:17 +06:00
マスターブランチにいたまま、新しいブランチを作成してください。
2020-02-13 09:13:04 +06:00
```sh
(master)$ git branch my-branch
```
2020-02-24 16:36:17 +06:00
マスターブランチを直前のコミットにリセットします。
2020-02-13 09:13:04 +06:00
```sh
(master)$ git reset --hard HEAD^
```
2020-02-24 16:36:17 +06:00
ここで `HEAD^``HEAD^1` の短縮形で、`HEAD` の第一の親を表します。
同様に `HEAD^2` は第二の親です(マージには親が二つあります)。
2020-02-13 09:13:04 +06:00
2020-02-24 16:36:17 +06:00
なお、`HEAD^2` は `HEAD~2` と**異なる**ことに注意してください(詳しくは[このリンク](http://www.paulboxley.com/blog/2011/06/git-caret-and-tilde)を参照してください)。
2020-02-13 09:13:04 +06:00
2020-02-24 16:36:17 +06:00
あるいは `HEAD^` を使いたくなければ、マスターブランチを差し戻したい先のコミットハッシュを探し(`git log` を使うとよいです)、そのハッシュにリセットします。
あとは `git push` すればリモートに反映されるはずです。
2020-02-13 09:13:04 +06:00
2020-02-24 16:36:17 +06:00
例えば、マスターブランチを差し戻したいコミットのハッシュが `a13b85e` なら、次のようにします。
2020-02-13 09:13:04 +06:00
```sh
(master)$ git reset --hard a13b85e
HEAD is now at a13b85e
```
2020-02-24 16:36:17 +06:00
作業に戻るため、新しいブランチにチェックアウトしましょう。
2020-02-13 09:13:04 +06:00
```sh
(master)$ git checkout my-branch
```
<a name="keep-whole-file"></a>
2020-02-15 08:02:54 +06:00
### ファイル全てをリファレンス的な場所に保存しておきたい
2020-02-13 09:13:04 +06:00
2020-02-24 16:36:17 +06:00
ワーキングスパイク(メモを参照)にたくさん編集があって、すべてうまく機能しているものとします。
2020-02-15 08:02:54 +06:00
この作業内容を保存しておくため、別のブランチにコミットします。
2020-02-13 09:13:04 +06:00
```sh
(solution)$ git add -A && git commit -m "Adding all changes from this spike into one big commit."
```
2020-02-24 16:36:17 +06:00
この内容をブランチ(フィーチャーブランチでも `develop` でも)に適用する際は、ファイル全部を保存しておきたいはずです。
2020-02-15 08:02:54 +06:00
大きなコミットを小さなコミットに分割します。
2020-02-13 09:13:04 +06:00
2020-02-15 08:02:54 +06:00
いま、次のブランチがあるものとします。
2020-02-13 09:13:04 +06:00
2020-02-24 16:36:17 +06:00
* `solution` ブランチ。スパイクを解消するためのブランチで、`develop` ブランチに対して一コミット分進んでいます。
2020-02-15 08:02:54 +06:00
* `develop` ブランチ。ここに編集内容を適用したいとします。
2020-02-13 09:13:04 +06:00
2020-02-15 08:02:54 +06:00
これは編集内容をブランチに適用することで可能です。
2020-02-13 09:13:04 +06:00
```sh
(develop)$ git checkout solution -- file1.txt
```
2020-02-24 16:36:17 +06:00
これで `solution` ブランチの内容が `develop` ブランチに適用されます。
2020-02-13 09:13:04 +06:00
```sh
# On branch develop
# Your branch is up-to-date with 'origin/develop'.
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: file1.txt
```
2020-02-15 08:02:54 +06:00
あとは通常通りコミットしてください。
2020-02-13 09:13:04 +06:00
2020-02-24 16:36:17 +06:00
メモ:スパイクは問題を解析したり解決するためのものです。
解決法は判断にかけられたあと、共同開発者が問題を理解した時点で破棄されます。~ [Wikipedia](https://en.wikipedia.org/wiki/Extreme_programming_practices)
2020-02-13 09:13:04 +06:00
<a name="cherry-pick"></a>
2020-02-15 08:02:54 +06:00
### 別々のブランチにするべき複数のコミットを一つのブランチにしてしまった
2020-02-13 09:13:04 +06:00
2020-02-15 08:02:54 +06:00
マスターブランチにいるとして、`git log` でコミットが二つ表示されるとします。
2020-02-13 09:13:04 +06:00
```sh
(master)$ git log
commit e3851e817c451cc36f2e6f3049db528415e3c114
Author: Alex Lee <alexlee@example.com>
Date: Tue Jul 22 15:39:27 2014 -0400
Bug #21 - Added CSRF protection
commit 5ea51731d150f7ddc4a365437931cd8be3bf3131
Author: Alex Lee <alexlee@example.com>
Date: Tue Jul 22 15:39:12 2014 -0400
Bug #14 - Fixed spacing on title
commit a13b85e984171c6e2a1729bb061994525f626d14
Author: Aki Rose <akirose@example.com>
Date: Tue Jul 21 01:12:48 2014 -0400
First commit
```
2020-02-15 08:02:54 +06:00
それぞれのバグに対応するコミットハッシュをメモしておきます(#21 は`e3851e8`、#14 は`5ea5173` です)。
2020-02-13 09:13:04 +06:00
2020-02-24 16:36:17 +06:00
まず、次のようにしてマスターブランチをあるべきコミット `a13b85e` までリセットします。
2020-02-13 09:13:04 +06:00
```sh
(master)$ git reset --hard a13b85e
HEAD is now at a13b85e
```
2020-02-24 16:36:17 +06:00
これで、バグ #21 に対応する新しいブランチを作成できます。
2020-02-13 09:13:04 +06:00
```sh
(master)$ git checkout -b 21
(21)$
```
2020-02-15 08:02:54 +06:00
さて、このブランチにコミットを**チェリーピック**しましょう。
つまり、head が何であろうとそこに当該コミットだけを適用します。
2020-02-13 09:13:04 +06:00
```sh
(21)$ git cherry-pick e3851e8
```
2020-02-24 16:36:17 +06:00
この時点で、コミットのコンフリクトが発生しているかもしれません。
コンフリクトを解消する方法は、[interactive rebasing section above](#interactive-rebase) セクションの [**There were conflicts**](#merge-conflict) を参照してください。
2020-02-13 09:13:04 +06:00
2020-02-24 16:36:17 +06:00
次に、#14 に対応する、マスターに紐づいたブランチを作成しましょう。
2020-02-13 09:13:04 +06:00
```sh
(21)$ git checkout master
(master)$ git checkout -b 14
(14)$
```
2020-02-15 08:02:54 +06:00
最後に、バグ #14 に対応するコミットをチェリーピックします。
2020-02-13 09:13:04 +06:00
```sh
(14)$ git cherry-pick 5ea5173
```
<a name="delete-stale-local-branches"></a>
2020-02-15 08:02:54 +06:00
### upstream で削除されたローカルブランチを削除したい
2020-02-24 16:36:17 +06:00
GitHub でプルリクエストをマージすると、マージされたブランチを自分のフォークから削除する選択肢が出てきます。
2020-02-15 08:02:54 +06:00
そのブランチで今後作業するつもりがなければ、もはや使わないブランチで作業環境が散らからないように削除しておくほうが綺麗です。
2020-02-13 09:13:04 +06:00
```sh
$ git fetch -p upstream
```
2020-02-15 08:02:54 +06:00
ここで `upstream` は取得したい元のリモートを指します。
2020-02-13 09:13:04 +06:00
<a name='restore-a-deleted-branch'></a>
2020-02-15 08:02:54 +06:00
### 間違ってブランチを削除してしまった
2020-02-13 09:13:04 +06:00
2020-02-24 16:36:17 +06:00
いつもリモートにプッシュしているなら大抵大丈夫です。
ブランチを間違って削除してしまうのはよくあることです。
2020-02-15 08:02:54 +06:00
2020-02-24 16:36:17 +06:00
新しくブランチを作り、ファイルを新規作成したとします。
2020-02-13 09:13:04 +06:00
```sh
(master)$ git checkout -b my-branch
(my-branch)$ git branch
(my-branch)$ touch foo.txt
(my-branch)$ ls
README.md foo.txt
```
2020-02-15 08:02:54 +06:00
これを追加してコミットします。
2020-02-13 09:13:04 +06:00
```sh
(my-branch)$ git add .
(my-branch)$ git commit -m 'foo.txt added'
(my-branch)$ foo.txt added
1 files changed, 1 insertions(+)
create mode 100644 foo.txt
(my-branch)$ git log
commit 4e3cd85a670ced7cc17a2b5d8d3d809ac88d5012
Author: siemiatj <siemiatj@example.com>
Date: Wed Jul 30 00:34:10 2014 +0200
foo.txt added
commit 69204cdf0acbab201619d95ad8295928e7f411d5
Author: Kate Hudson <katehudson@example.com>
Date: Tue Jul 29 13:14:46 2014 -0400
Fixes #6: Force pushing after amending commits
```
2020-02-15 08:02:54 +06:00
マスターに戻って、「間違って」ブランチを削除してみます。
2020-02-13 09:13:04 +06:00
```sh
(my-branch)$ git checkout master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
(master)$ git branch -D my-branch
Deleted branch my-branch (was 4e3cd85).
(master)$ echo oh noes, deleted my branch!
oh noes, deleted my branch!
```
2020-02-24 16:36:17 +06:00
さて、ここで改良されたロガー `reflog` について学びましょう。
これはリポジトリの全ての操作履歴を保存しています。
2020-02-13 09:13:04 +06:00
```
(master)$ git reflog
69204cd HEAD@{0}: checkout: moving from my-branch to master
4e3cd85 HEAD@{1}: commit: foo.txt added
69204cd HEAD@{2}: checkout: moving from master to my-branch
```
2020-02-24 16:36:17 +06:00
このように、削除してしまったブランチのコミットが表示されています。
削除したブランチを復元してみましょう。
2020-02-13 09:13:04 +06:00
```sh
(master)$ git checkout -b my-branch-help
Switched to a new branch 'my-branch-help'
(my-branch-help)$ git reset --hard 4e3cd85
HEAD is now at 4e3cd85 foo.txt added
(my-branch-help)$ ls
README.md foo.txt
```
2020-02-24 16:36:17 +06:00
やった! 消えたファイルを取り戻しました。
コマンド `git reflog` は、リベースが滅茶苦茶になってしまったときにも便利です。
2020-02-13 09:13:04 +06:00
2020-02-15 08:02:54 +06:00
### ブランチを削除したい
2020-02-13 09:13:04 +06:00
2020-02-24 16:36:17 +06:00
リモートブランチを削除するには次を実行します。
2020-02-13 09:13:04 +06:00
```sh
(master)$ git push origin --delete my-branch
```
2020-02-24 16:36:17 +06:00
次のようにもできます。
2020-02-13 09:13:04 +06:00
```sh
(master)$ git push origin :my-branch
```
2020-02-24 16:36:17 +06:00
ローカルブランチを削除するには次の通りです。
2020-02-13 09:13:04 +06:00
```sh
(master)$ git branch -d my-branch
```
2020-02-24 16:36:17 +06:00
現在のブランチか upstream にマージ**されていない**ブランチを削除するには次のようにします。
2020-02-13 09:13:04 +06:00
```sh
(master)$ git branch -D my-branch
```
2020-02-15 08:02:54 +06:00
### 複数のブランチを削除したい
2020-02-13 09:13:04 +06:00
2020-02-24 16:36:17 +06:00
名前が `fix/` で始まるブランチを全て削除したいときは次の通りです。
2020-02-13 09:13:04 +06:00
```sh
(master)$ git branch | grep 'fix/' | xargs git branch -d
```
2020-02-15 08:02:54 +06:00
### ブランチの名前を変更したい
2020-02-13 09:13:04 +06:00
2020-02-24 16:36:17 +06:00
現在の(ローカル)ブランチの名前を変更するには次を実行します。
2020-02-13 09:13:04 +06:00
```sh
(master)$ git branch -m new-name
```
2020-02-24 16:36:17 +06:00
現在いるブランチと異なる(ローカル)ブランチの名前を変更するには次のようにします。
2020-02-13 09:13:04 +06:00
```sh
(master)$ git branch -m old-name new-name
```
2020-02-15 08:02:54 +06:00
2020-02-24 16:36:17 +06:00
古い名前(`old-name`)のリモートブランチを削除し、新しい名前(`new-name`)のブランチをプッシュするには次の通りです。
2020-02-13 09:13:04 +06:00
2020-02-15 08:02:54 +06:00
```sh
(master)$ git push origin :old_name new_name
```
2020-02-13 09:13:04 +06:00
<a name="i-want-to-checkout-to-a-remote-branch-that-someone-else-is-working-on"></a>
2020-02-15 08:02:54 +06:00
### 他の人が作業しているリモートブランチにチェックアウトしたい
2020-02-13 09:13:04 +06:00
2020-02-24 16:36:17 +06:00
まず、リモートから全ブランチを取得します。
2020-02-13 09:13:04 +06:00
```sh
(master)$ git fetch --all
```
2020-02-15 08:02:54 +06:00
リモートブランチ `daves` にチェックアウトしたいとします。
2020-02-13 09:13:04 +06:00
```sh
(master)$ git checkout --track origin/daves
Branch daves set up to track remote branch daves from origin.
Switched to a new branch 'daves'
```
2020-02-15 08:02:54 +06:00
(ここで `--track``git checkout -b [branch] [remotename]/[branch]` の短縮形です。)
2020-02-13 09:13:04 +06:00
2020-02-24 16:36:17 +06:00
これでローカルにブランチ `daves` のコピーが作成され、プッシュした編集内容がリモートに反映されるようになります。
2020-02-13 09:13:04 +06:00
2020-02-15 08:02:54 +06:00
### 現在のローカルブランチをもとに新しいリモートブランチを作成したい
2020-02-13 09:13:04 +06:00
```sh
$ git push <remote> HEAD
```
2020-02-24 16:36:17 +06:00
同時にこのリモートブランチを現在のブランチの upstream に設定したい場合は、代わりに次を実行します。
2020-02-13 09:13:04 +06:00
```sh
$ git push -u <remote> HEAD
```
2020-02-24 16:36:17 +06:00
`push.default` の設定が `upstream` モードか `simple` モードGit 2.0 のデフォルト)になっている場合、次のコマンドを実行すると、以前に `-u` で登録したリモートブランチに現在のブランチをプッシュします。
2020-02-13 09:13:04 +06:00
```sh
$ git push
```
2020-02-24 16:36:17 +06:00
他のモードが `git push` でどう振る舞うかは、[`push.default` のドキュメント](https://git-scm.com/docs/git-config#git-config-pushdefault)で説明されています。
2020-02-13 09:13:04 +06:00
2020-02-15 08:02:54 +06:00
### リモートブランチをローカルブランチの upstream に設定したい
2020-02-13 09:13:04 +06:00
2020-02-15 08:02:54 +06:00
次のようにして、リモートブランチを現在いるローカルブランチの upstream に設定できます。
2020-02-13 09:13:04 +06:00
```sh
$ git branch --set-upstream-to [remotename]/[branch]
# or, using the shorthand:
$ git branch -u [remotename]/[branch]
```
2020-02-24 16:36:17 +06:00
別のローカルブランチの upstream に設定するには次のようにします。
2020-02-13 09:13:04 +06:00
```sh
$ git branch -u [remotename]/[branch] [local-branch]
```
<a name="i-want-to-set-my-HEAD-to-track-the-default-remote-branch"></a>
2020-02-15 08:02:54 +06:00
### 自分の HEAD をデフォルトのリモートブランチを追跡するよう設定したい
2020-02-13 09:13:04 +06:00
2020-02-15 08:02:54 +06:00
リモートブランチを調べると、自分の HEAD がどのリモートブランチを追跡しているかがわかります。
ときどきこれが追跡したいブランチと異なることがあります。
2020-02-13 09:13:04 +06:00
```sh
$ git branch -r
origin/HEAD -> origin/gh-pages
origin/master
```
2020-02-24 16:36:17 +06:00
`origin/HEAD``origin/master` を追跡するよう設定し直すには、次を実行します:
2020-02-13 09:13:04 +06:00
```sh
$ git remote set-head origin --auto
origin/HEAD set to master
```
2020-02-15 08:02:54 +06:00
### 間違ったブランチを編集してしまった
2020-02-13 09:13:04 +06:00
2020-02-15 08:02:54 +06:00
まだコミットしていない編集を加えたあと、間違ったブランチにいることに気づいたとします。
編集内容をスタッシュして、適切なブランチに適用すれば大丈夫です:
2020-02-13 09:13:04 +06:00
```sh
(wrong_branch)$ git stash
(wrong_branch)$ git checkout <correct_branch>
(correct_branch)$ git stash apply
```
2020-02-16 07:57:43 +06:00
## リベースとマージ
2020-02-13 09:13:04 +06:00
<a name="undo-rebase"></a>
2020-02-16 07:57:43 +06:00
### リベースやマージを取り消したい
2020-02-13 09:13:04 +06:00
2020-02-27 18:53:30 +06:00
現在のブランチを間違ったブランチにリベースないしマージしてしまった、あるいはリベースないしマージができなさそうだと気づいたとしましょう。
2020-02-16 07:57:43 +06:00
Git は危険な操作の前に HEAD が指すものを変数 `ORIG_HEAD` に保存しているので、ブランチをリベースないしマージの前の状態に差し戻すのは簡単です。
2020-02-13 09:13:04 +06:00
```sh
(my-branch)$ git reset --hard ORIG_HEAD
```
<a name="force-push-rebase"></a>
2020-02-16 07:57:43 +06:00
### リベースしたが、強制プッシュはしたくない
2020-02-13 09:13:04 +06:00
2020-02-27 18:53:30 +06:00
残念ながら、編集をリモートブランチに反映させるには強制プッシュをする必要があります。
編集履歴を変えてしまったからです。
強制プッシュしない限り、リモートブランチは編集内容を受け付けません。
2020-02-16 07:57:43 +06:00
これが多くの人がリベースワークフローではなくマージワークフローを使う主な理由です。
2020-02-27 18:53:30 +06:00
特に大規模な開発チームは強制プッシュでハマりやすいです。
2020-02-16 07:57:43 +06:00
リベースの強制プッシュは注意して使いましょう。
2020-02-27 18:53:30 +06:00
リベースの安全な使い方は、リモートには編集内容を反映させずに、代わりに次を実行することです。
2020-02-13 09:13:04 +06:00
```sh
(master)$ git checkout my-branch
(my-branch)$ git rebase -i master
(my-branch)$ git checkout master
(master)$ git merge --ff-only my-branch
```
2020-02-16 07:57:43 +06:00
詳しくは[この StackOverflow スレッド](https://stackoverflow.com/questions/11058312/how-can-i-use-git-rebase-without-requiring-a-forced-push)を参照してください。
2020-02-13 09:13:04 +06:00
<a name="interactive-rebase"></a>
2020-02-16 07:57:43 +06:00
### コミットを統合したい
2020-02-27 18:53:30 +06:00
`master` ブランチにプルリクエストを送る、あるいはこれから送るつもりのブランチで作業しているとします。
最も単純なケースとして、タイムスタンプを気にせずコミット**全部**を一つにまとめたいとします。
この場合はリセットと再コミットを行います。
マスターブランチが最新版で、編集内容がすべてコミットされていることを確認した上で、次を実行してください。
2020-02-13 09:13:04 +06:00
```sh
(my-branch)$ git reset --soft master
(my-branch)$ git commit -am "New awesome feature"
```
2020-02-27 18:53:30 +06:00
もっと細かく設定し、タイムスタンプも残したい場合は、対話的リベースを使います。
2020-02-13 09:13:04 +06:00
```sh
(my-branch)$ git rebase -i master
```
2020-02-27 18:53:30 +06:00
別のブランチで作業しているわけではない場合、`HEAD` に対してリベースする必要があります。
たとえば直近二件のコミットを圧縮 (squash) したい場合は `HEAD~2`、直近三件なら `HEAD~3` です。
2020-02-13 09:13:04 +06:00
```sh
(master)$ git rebase -i HEAD~2
```
2020-02-27 18:53:30 +06:00
対話的リベースのコマンドを実行したら、テキストエディタに次のように表示されます。
2020-02-13 09:13:04 +06:00
```vim
pick a9c8a1d Some refactoring
pick 01b2fd8 New awesome feature
pick b729ad5 fixup
pick e3851e8 another fix
# Rebase 8074d12..b729ad5 onto 8074d12
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
```
2020-02-16 07:57:43 +06:00
ここで `#` から始まる行はコメントなので、リベースに影響しません。
2020-02-13 09:13:04 +06:00
2020-02-27 18:53:30 +06:00
コマンド `pick` をリストの好きなコマンドで書きかえればよいです。
行を削除すればコミットを削除できます。
2020-02-13 09:13:04 +06:00
2020-02-27 18:53:30 +06:00
例えば、**一番古い(一番目の)コミットはそのまま残し、他のコミット全てを二番目のコミットに統合したい**場合は、最初と二番目以外のコミットの横の文字を `f` に書きかえます。
2020-02-13 09:13:04 +06:00
```vim
pick a9c8a1d Some refactoring
pick 01b2fd8 New awesome feature
f b729ad5 fixup
f e3851e8 another fix
```
2020-02-27 18:53:30 +06:00
コミットを統合し、**さらに名前も変更したい**場合は、二番目のコミットの横にさらに `r` の文字を追加するか、あるいは単に `f` の代わりに `s` を使います。
2020-02-13 09:13:04 +06:00
```vim
pick a9c8a1d Some refactoring
pick 01b2fd8 New awesome feature
s b729ad5 fixup
s e3851e8 another fix
```
2020-02-16 07:57:43 +06:00
するとテキストエディタが起動し、コミットの名前を変更できます。
2020-02-13 09:13:04 +06:00
```vim
Newer, awesomer features
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# rebase in progress; onto 8074d12
# You are currently editing a commit while rebasing branch 'master' on '8074d12'.
#
# Changes to be committed:
# modified: README.md
#
```
2020-02-27 18:53:30 +06:00
うまくいくと次のように表示されるはずです。
2020-02-13 09:13:04 +06:00
```sh
(master)$ Successfully rebased and updated refs/heads/master.
```
2020-02-16 07:57:43 +06:00
#### 安全なマージの方法
2020-02-27 18:53:30 +06:00
オプション `--no-commit` を指定すると、マージを実行しつつ、あたかもマージが失敗したかのように扱って自動コミットはしません。
これにより、コミットの前にマージの結果を精査したり調整できます。
オプション `--no-ff` はフィーチャーブランチが存在したことを記録に残しておき、プロジェクト履歴の一貫性を保ちます。
2020-02-13 09:13:04 +06:00
```sh
(master)$ git merge --no-ff --no-commit my-branch
```
2020-02-16 07:57:43 +06:00
#### ブランチを一つのコミットにまとめたい場合
2020-02-13 09:13:04 +06:00
```sh
(master)$ git merge --squash my-branch
```
<a name="rebase-unpushed-commits"></a>
2020-02-16 07:57:43 +06:00
#### プッシュされていないコミットのみを統合したい場合
2020-02-13 09:13:04 +06:00
2020-02-27 18:53:30 +06:00
進行中の作業に関するコミットがいくつかあって、upstream にコミットする前に統合しておきたいとします。
2020-02-16 07:57:43 +06:00
すでに upstream にプッシュされたコミットは、誰かがそれを参照するコミットをしている可能性があるので、それは統合しないでおきたいとします。
2020-02-13 09:13:04 +06:00
```sh
(master)$ git rebase -i @{u}
```
2020-02-27 18:53:30 +06:00
上を実行すると対話的リベースが始まりますが、一覧にはまだプッシュされていないコミットだけが表示されます。
これで順番を入れ替えたり、修正したり、圧縮 (squash) したりしても安全です。
2020-02-13 09:13:04 +06:00
2020-02-16 07:57:43 +06:00
#### マージを中止したい
2020-02-13 09:13:04 +06:00
2020-02-16 07:57:43 +06:00
マージがファイルに問題をきたすことがあります。
こういうときはオプション `abort` を使うとコンフリクト解消の作業を中止し、マージの前の状態の復元を試みることができます。
2020-02-13 09:13:04 +06:00
```sh
(my-branch)$ git merge --abort
```
2020-02-27 18:53:30 +06:00
ただし、このコマンドが使えるのはバージョン 1.7.4 以上の Git に限ります。
2020-02-13 09:13:04 +06:00
2020-02-16 07:57:43 +06:00
### ブランチの親コミットを更新したい
2020-02-13 09:13:04 +06:00
2020-02-16 07:57:43 +06:00
マスターブランチとそこから分岐した feature-1 ブランチがあり、feature-1 からさらに分岐した feature-2 ブランチがあるとします。
2020-02-27 18:53:30 +06:00
いま feature-1 ブランチにコミットしたとすると、feature-2 ブランチの親コミットはもはや正確ではありませんfeature-1 から分岐したので、親コミットは feature-1 ブランチの head であるべきです。)
2020-02-16 07:57:43 +06:00
こういうときは `git rebase --onto` で修正できます。
2020-02-13 09:13:04 +06:00
```sh
(feature-2)$ git rebase --onto feature-1 <the first commit in your feature-2 branch that you don't want to bring along> feature-2
```
2020-02-16 07:57:43 +06:00
まだマージされていないブランチからフィーチャーブランチを分岐させており、feature-1 ブランチのバグ修正を feature-2 に反映させたいときに便利です。
2020-02-13 09:13:04 +06:00
2020-02-16 07:57:43 +06:00
### ブランチの全コミットがマージされているか確認する
2020-02-13 09:13:04 +06:00
2020-02-27 18:53:30 +06:00
ブランチの全コミットが別のブランチにマージされているか確認するには、それぞれのブランチの headあるいは任意のコミットの間の差分を表示します。
2020-02-13 09:13:04 +06:00
```sh
(master)$ git log --graph --left-right --cherry-pick --oneline HEAD...feature/120-on-scroll
```
2020-02-27 18:53:30 +06:00
一方のブランチにしかないコミットがあるか表示され、ブランチ間で共有されていないコミットの一覧がわかります。
もう一つの方法は次の通りです。
2020-02-13 09:13:04 +06:00
```sh
(master)$ git log master ^feature/120-on-scroll --no-merges
```
2020-02-16 07:57:43 +06:00
### 対話的リベースで起こりうる問題
2020-02-13 09:13:04 +06:00
<a name="noop"></a>
2020-02-16 07:57:43 +06:00
#### リベース編集画面に 'noop' と表示される
2020-02-27 18:53:30 +06:00
次のように表示された場合です。
2020-02-13 09:13:04 +06:00
```
noop
```
2020-02-27 18:53:30 +06:00
これは、同じコミットのブランチ、あるいは現在のブランチよりも*先*にあるブランチに対してリベースしようとしたときに表示されます。
この場合は、
2020-02-13 09:13:04 +06:00
2020-02-27 18:53:30 +06:00
* マスターブランチが正しい場所にあることを確認してください。
* `HEAD~2` あるいはより以前にリベースしてください。
2020-02-13 09:13:04 +06:00
<a name="merge-conflict"></a>
2020-02-16 07:57:43 +06:00
#### コンフリクトがあった
2020-02-13 09:13:04 +06:00
2020-02-16 07:57:43 +06:00
リベースができないときは、解消すべきコンフリクトがあるかもしれません。
2020-02-13 09:13:04 +06:00
2020-02-27 18:53:30 +06:00
まず `git status` で、どのファイルがコンフリクトを起こしているか確認します。
2020-02-13 09:13:04 +06:00
```sh
(my-branch)$ git status
On branch my-branch
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
both modified: README.md
```
2020-02-27 18:53:30 +06:00
この例では `README.md` にコンフリクトがあります。
ファイルを開き、次のようになっている箇所を見てみましょう。
2020-02-13 09:13:04 +06:00
```vim
<<<<<<< HEAD
some code
=========
some code
>>>>>>> new-commit
```
2020-02-27 18:53:30 +06:00
`HEAD` と新しいコミットで加えられたコードの間の差分(この例では、真ん中の行から `new-commit` の間にあるコード)を解消する必要があります。
2020-02-13 09:13:04 +06:00
2020-02-16 07:57:43 +06:00
一方のブランチの版のコードを残したい場合は、`--ours` あるいは `--theirs` を指定します。
2020-02-13 09:13:04 +06:00
```sh
(master*)$ git checkout --ours README.md
```
2020-02-16 07:57:43 +06:00
- *マージする*場合、ローカルブランチの編集内容を残したいとき `--ours` を指定し、他方の編集内容を残したいとき `--theirs` を指定します。
2020-02-27 18:53:30 +06:00
- *リベースする*場合、ローカルブランチの編集内容を残したいとき `--theirs` を指定し、他方の編集内容を残したいとき `--ours` を指定します。このように逆転する理由は[ Git ドキュメントのこのノート](https://git-scm.com/docs/git-rebase#git-rebase---merge)を参照してください。
2020-02-13 09:13:04 +06:00
2020-02-27 18:53:30 +06:00
マージがもっと複雑なときは、ビジュアル差分エディタを使うとよいです。
2020-02-13 09:13:04 +06:00
```sh
(master*)$ git mergetool -t opendiff
```
2020-02-16 07:57:43 +06:00
コンフリクトを全て解消し、コードのテストが済んだら、`git add ` で編集内容をステージし、`git rebase --continue` でリベースを再開します。
2020-02-13 09:13:04 +06:00
```sh
(my-branch)$ git add README.md
(my-branch)$ git rebase --continue
```
2020-02-16 07:57:43 +06:00
コンフリクトを解消した結果、ワーキングツリーがコミット前と全く同じ状態になった場合は、代わりに `git rebase --skip` を実行します。
2020-02-13 09:13:04 +06:00
2020-02-27 18:53:30 +06:00
リベース作業を全て中止し、ブランチを元の状態に差し戻したい場合は、次を実行します。
2020-02-13 09:13:04 +06:00
```sh
(my-branch)$ git rebase --abort
```
<a name="stashing"></a>
2020-02-17 18:22:39 +06:00
## スタッシュ
2020-02-13 09:13:04 +06:00
2020-02-17 18:22:39 +06:00
### 全ての編集内容をスタッシュしたい
2020-02-13 09:13:04 +06:00
2020-02-27 18:57:28 +06:00
ワーキングディレクトリの編集を全てスタッシュするには、次を実行します。
2020-02-13 09:13:04 +06:00
```sh
$ git stash
```
2020-02-27 18:57:28 +06:00
バージョン管理されていないファイルもスタッシュしたいときは、オプション `-u` を指定します。
2020-02-13 09:13:04 +06:00
```sh
$ git stash -u
```
2020-02-17 18:22:39 +06:00
### 特定のファイルをスタッシュしたい
2020-02-13 09:13:04 +06:00
2020-02-27 18:57:28 +06:00
ワーキングディレクトリのファイル一つをスタッシュするには、次を実行します。
2020-02-13 09:13:04 +06:00
```sh
$ git stash push working-directory-path/filename.ext
```
2020-02-27 18:57:28 +06:00
ワーキングディレクトリの複数のファイルをスタッシュするときは次の通りです。
2020-02-13 09:13:04 +06:00
```sh
$ git stash push working-directory-path/filename1.ext working-directory-path/filename2.ext
```
<a name="stash-msg"></a>
2020-02-17 18:22:39 +06:00
### メッセージをつけてスタッシュしたい
2020-02-13 09:13:04 +06:00
```sh
$ git stash save <message>
```
2020-02-27 18:57:28 +06:00
あるいは次の通りです。
2020-02-13 09:13:04 +06:00
```sh
$ git stash push -m <message>
```
<a name="stash-apply-specific"></a>
2020-02-17 18:22:39 +06:00
### 一覧から特定のスタッシュを選んで適用したい
2020-02-13 09:13:04 +06:00
2020-02-17 18:22:39 +06:00
まず、次のようにしてスタッシュの一覧をメッセージとともに表示します。
2020-02-13 09:13:04 +06:00
```sh
$ git stash list
```
2020-02-27 18:57:28 +06:00
そして、次のようにして特定のスタッシュを選び適用します。
2020-02-13 09:13:04 +06:00
```sh
$ git stash apply "stash@{n}"
```
2020-02-27 18:57:28 +06:00
ここで、`n` は一覧の中のスタッシュの位置を指します。一番上のスタッシュなら 0 番です。
2020-02-13 09:13:04 +06:00
2020-02-27 18:57:28 +06:00
また、時刻からスタッシュを指定することもできます。
2020-02-13 09:13:04 +06:00
```sh
$ git stash apply "stash@{2.hours.ago}"
```
<a name="stage-and-keep-unstaged"></a>
2020-02-17 18:22:39 +06:00
### ステージされていない編集をそのままにしつつ、スタッシュしたい
2020-02-13 09:13:04 +06:00
2020-02-17 18:22:39 +06:00
手動で `stash commit` を作成し、`git stash store` を実行すればよいです。
2020-02-13 09:13:04 +06:00
```sh
$ git stash create
$ git stash store -m <message> CREATED_SHA1
```
2020-02-17 19:00:30 +06:00
## 検索
2020-02-13 09:13:04 +06:00
2020-02-27 19:01:32 +06:00
### 全コミットから文字列を検索したい
2020-02-13 09:13:04 +06:00
2020-02-27 19:01:32 +06:00
どこかのコミットで導入された文字列を検索したいときは、次のコマンドを使います。
2020-02-13 09:13:04 +06:00
```sh
$ git log -S "string to find"
```
2020-02-27 19:01:32 +06:00
よく使われるパラメータは次の通りです。
2020-02-13 09:13:04 +06:00
2020-02-27 19:01:32 +06:00
* `--source` はコマンドラインでつけられた各コミットの参照名を表示します。
2020-02-17 19:00:30 +06:00
* `--all` は全てのブランチから検索します。
2020-02-27 19:01:32 +06:00
* `--reverse` は逆順に表示します。すなわち最初のコミットから表示します。
2020-02-13 09:13:04 +06:00
<a name="i-want-to-find-by-author-committer"></a>
2020-02-17 19:00:30 +06:00
### author または committer から検索する
2020-02-13 09:13:04 +06:00
2020-02-27 19:01:32 +06:00
全てのコミットを author または committer の名前から検索するには次のようにします。
2020-02-13 09:13:04 +06:00
```sh
$ git log --author=<name or email>
$ git log --committer=<name or email>
```
2020-02-27 19:01:32 +06:00
なお、author と committer は異なることに注意してください。
2020-02-17 19:00:30 +06:00
`--author` ははじめにコードを書いた人、`--committer` は author の代わりにコミットした人を指します。
2020-02-13 09:13:04 +06:00
2020-02-17 19:00:30 +06:00
### 特定のファイルを含むコミットの一覧を表示したい
2020-02-13 09:13:04 +06:00
2020-02-17 19:00:30 +06:00
特定のファイルを含むコミットの一覧を表示するには、次を実行します。
2020-02-13 09:13:04 +06:00
```sh
$ git log -- <path to file>
```
2020-02-27 19:01:32 +06:00
通常は正確なパスを指定しますが、パスやファイル名にワイルドカードを使うこともできます。
2020-02-13 09:13:04 +06:00
```sh
$ git log -- **/*.js
```
2020-02-27 19:01:32 +06:00
ワイルドカードを使う際は、`--name-status` を指定すると、コミットされたファイルの一覧が表示されて便利です。
2020-02-13 09:13:04 +06:00
```sh
$ git log --name-status -- **/*.js
```
<a name="#i-want-to-view-the-commit-history-for-a-specific-function"></a>
2020-02-27 19:01:32 +06:00
### 特定の関数に関するコミット履歴を見たい
2020-02-13 09:13:04 +06:00
2020-02-27 19:01:32 +06:00
特定の関数の履歴を追跡するには次を実行します。
2020-02-13 09:13:04 +06:00
```sh
$ git log -L :FunctionName:FilePath
```
2020-02-17 19:00:30 +06:00
このコマンドは `git log` の他のオプション、例えば [revision ranges](https://git-scm.com/docs/gitrevisions) や [commit limits](https://git-scm.com/docs/git-log/#_commit_limiting) と一緒に使うことができます。
2020-02-13 09:13:04 +06:00
2020-02-17 19:00:30 +06:00
### コミットが参照されているタグを検索したい
2020-02-13 09:13:04 +06:00
2020-02-27 19:01:32 +06:00
特定のコミットを含むタグを検索するには次のようにします。
2020-02-13 09:13:04 +06:00
```sh
$ git tag --contains <commitid>
```
2020-02-20 18:17:40 +06:00
## サブモジュール
2020-02-13 09:13:04 +06:00
<a name="clone-submodules"></a>
2020-02-20 18:17:40 +06:00
### 全てのサブモジュールをクローンする
2020-02-13 09:13:04 +06:00
```sh
$ git clone --recursive git://github.com/foo/bar.git
```
2020-02-27 19:02:48 +06:00
すでにクローンしている場合は次の通りです。
2020-02-13 09:13:04 +06:00
```sh
$ git submodule update --init --recursive
```
<a name="delete-submodule"></a>
2020-02-20 18:17:40 +06:00
### サブモジュールを削除する
2020-02-13 09:13:04 +06:00
2020-02-20 18:17:40 +06:00
サブモジュールの作成はきわめて簡単ですが、削除はそうでもありません。
2020-02-27 19:02:48 +06:00
削除に必要なコマンドは次の通りです。
2020-02-13 09:13:04 +06:00
```sh
$ git submodule deinit submodulename
$ git rm submodulename
$ git rm --cached submodulename
$ rm -rf .git/modules/submodulename
```
2020-02-20 18:37:19 +06:00
## その他色々
2020-02-13 09:13:04 +06:00
2020-02-20 18:37:19 +06:00
### あるブランチから別のブランチにフォルダをコピーしたい
2020-02-13 09:13:04 +06:00
```sh
$ git checkout <branch-you-want-the-directory-from> -- <folder-name or file-name>
```
2020-02-20 18:37:19 +06:00
### 削除されたファイルを復元したい
2020-02-13 09:13:04 +06:00
2020-02-27 19:05:23 +06:00
まず、ファイルが最後に存在していたコミットを探します。
2020-02-13 09:13:04 +06:00
```sh
$ git rev-list -n 1 HEAD -- filename
```
2020-02-27 19:05:23 +06:00
見つけたら、ファイルをチェックアウトします。
2020-02-13 09:13:04 +06:00
```
git checkout deletingcommitid^ -- filename
```
2020-02-20 18:37:19 +06:00
### タグを削除したい
2020-02-13 09:13:04 +06:00
```sh
$ git tag -d <tag_name>
$ git push <remote> :refs/tags/<tag_name>
```
<a name="recover-tag"></a>
2020-02-20 18:37:19 +06:00
### 削除されたタグを復元したい
2020-02-13 09:13:04 +06:00
2020-02-20 18:37:19 +06:00
削除されたタグを復元する手順は次の通りです。
2020-02-27 19:05:23 +06:00
まず、unreachable になったタグを探します。
2020-02-13 09:13:04 +06:00
```sh
$ git fsck --unreachable | grep tag
```
2020-02-20 18:37:19 +06:00
タグのハッシュをメモしておきます。
2020-02-27 19:05:23 +06:00
続いて、次のように [`git update-ref`](https://git-scm.com/docs/git-update-ref) で削除されたタグを復元します。
2020-02-13 09:13:04 +06:00
```sh
$ git update-ref refs/tags/<tag_name> <hash>
```
2020-02-20 18:37:19 +06:00
これでタグが復元されたはずです。
2020-02-13 09:13:04 +06:00
2020-02-20 18:37:19 +06:00
### 削除されたパッチを取得したい
2020-02-13 09:13:04 +06:00
2020-02-27 19:05:23 +06:00
誰かが GitHub でプルリクエストを送ったあとにフォークを削除してしまった場合、そのリポジトリをクローンしたり、`git am` でパッチを適用することができなくなります。
[.diff や .patch](https://github.com/blog/967-github-secrets) の URL が使えなくなってしまうためです。
2020-02-20 18:37:19 +06:00
しかし、[GitHub 独自の参照](https://gist.github.com/piscisaureus/3342247)を使って、プルリクエスト自体をチェックアウトすることができます。
2020-02-27 19:05:23 +06:00
プルリクエスト #1 の内容を新しいブランチ pr_1 に取得するには、次を実行します。
2020-02-13 09:13:04 +06:00
```sh
$ git fetch origin refs/pull/1/head:pr_1
From github.com:foo/bar
* [new ref] refs/pull/1/head -> pr_1
```
2020-02-27 19:05:23 +06:00
### リポジトリを zip ファイルとしてエクスポートしたい
2020-02-13 09:13:04 +06:00
```sh
$ git archive --format zip --output /full/path/to/zipfile.zip master
```
2020-02-20 18:37:19 +06:00
### 同じ名前のブランチとタグをプッシュしたい
2020-02-27 19:05:23 +06:00
ブランチと同じ名前のタグがリモートリポジトリに存在する場合、通常通り `git push <remote> <branch>` でプッシュしようとすると、次のようなエラーが出ます。
2020-02-13 09:13:04 +06:00
```sh
$ git push origin <branch>
error: dst refspec same matches more than one.
error: failed to push some refs to '<git server>'
```
2020-02-27 19:05:23 +06:00
このエラーはブランチのヘッドを指定することで回避できます。
2020-02-13 09:13:04 +06:00
```sh
$ git push origin refs/heads/<branch-name>
```
2020-02-20 18:37:19 +06:00
同名のブランチがリモートリポジトリにあるタグをプッシュしたいときも、似たコマンドを使います。
2020-02-13 09:13:04 +06:00
```sh
$ git push origin refs/tags/<tag-name>
```
2020-02-20 18:55:36 +06:00
## ファイルの追跡
2020-02-13 09:13:04 +06:00
<a href="i-want-to-change-a-file-names-capitalization-without-changing-the-contents-of-the-file"></a>
2020-02-20 18:55:36 +06:00
### ファイルの内容は変えずに、ファイル名の大文字・小文字を変更したい
2020-02-13 09:13:04 +06:00
```sh
(master)$ git mv --force myfile MyFile
```
2020-02-20 18:55:36 +06:00
### git pull してローカルのファイルを上書きしたい
2020-02-13 09:13:04 +06:00
```sh
(master)$ git fetch --all
(master)$ git reset --hard origin/master
```
<a href="remove-from-git"></a>
2020-02-20 18:55:36 +06:00
### ファイルを残しつつ Git から削除したい
2020-02-13 09:13:04 +06:00
```sh
(master)$ git rm --cached log.txt
```
2020-02-20 18:55:36 +06:00
### ファイルを特定の版まで差し戻したい
2020-02-13 09:13:04 +06:00
2020-02-20 18:55:36 +06:00
差し戻したいコミットのハッシュが c5f567 の場合、次を実行します:
2020-02-13 09:13:04 +06:00
```sh
(master)$ git checkout c5f567 -- file1/to/restore file2/to/restore
```
2020-02-20 18:55:36 +06:00
差し戻したいコミットが c5f567 の一つ前なら、コミットハッシュに c5f567~1 を指定します:
2020-02-13 09:13:04 +06:00
```sh
(master)$ git checkout c5f567~1 -- file1/to/restore file2/to/restore
```
2020-02-20 18:55:36 +06:00
### 特定のファイルのコミット間・ブランチ間の差分を表示したい
2020-02-13 09:13:04 +06:00
2020-02-20 18:55:36 +06:00
コミット c5f567 とその一つ前の差分を表示したい場合、次を実行します:
2020-02-13 09:13:04 +06:00
```sh
$ git diff HEAD:path_to_file/file c5f567:path_to_file/file
```
2020-02-20 18:55:36 +06:00
ブランチでも同様です:
2020-02-13 09:13:04 +06:00
```sh
$ git diff master:path_to_file/file staging:path_to_file/file
```
2020-02-20 18:55:36 +06:00
### 特定のファイルの変更を無視したい
2020-02-13 09:13:04 +06:00
2020-02-20 18:55:36 +06:00
これはコミットできない認証情報をローカル環境で追加する必要のある設定テンプレートなどがあるときに役立ちます。
2020-02-13 09:13:04 +06:00
```sh
$ git update-index --assume-unchanged file-to-ignore
```
2020-02-20 18:55:36 +06:00
ファイルがバージョン管理されなくなるわけでは*ない*ことに注意してください。ローカルで無視されるだけです。
設定を取り消して変更を再び追跡するには、次のようにして ignore フラッグを削除します:
2020-02-13 09:13:04 +06:00
```sh
$ git update-index --no-assume-unchanged file-to-stop-ignoring
```
2020-02-20 19:12:26 +06:00
## Git によるデバッグ
2020-02-13 09:13:04 +06:00
2020-02-20 19:12:26 +06:00
コマンド [git-bisect](https://git-scm.com/docs/git-bisect) は、どのコミットがバグをもたらしたか Git 履歴を二分探索します。
2020-02-13 09:13:04 +06:00
2020-02-20 19:12:26 +06:00
`master` ブランチにいるとして、失敗をやらかしたコミットを探してみましょう。次のようにして二分探索を始めます:
2020-02-13 09:13:04 +06:00
```sh
$ git bisect start
```
2020-02-20 19:12:26 +06:00
問題のあるコミットとないコミットを指定する必要があります。*現在の*バージョンに問題があり、`v1.1.1` は問題ないとします。
2020-02-13 09:13:04 +06:00
```sh
$ git bisect bad
$ git bisect good v1.1.1
```
2020-02-20 19:12:26 +06:00
すると `git-bisect` は選んだバージョンの中間のコミットを選んで調べ、問題があるかどうか尋ねてきます。
次のように表示されるはずです:
2020-02-13 09:13:04 +06:00
```sh
$ Bisecting: 5 revision left to test after this (roughly 5 step)
$ [c44abbbee29cb93d8499283101fe7c8d9d97f0fe] Commit message
$ (c44abbb)$
```
2020-02-20 19:12:26 +06:00
このコミットに問題があるかどうか調べます。問題がない (good) 場合は次を実行します:
2020-02-13 09:13:04 +06:00
```sh
$ (c44abbb)$ git bisect good
```
2020-02-20 19:12:26 +06:00
すると、`git-bisect` は別のコミットを選択します。このように `good``bad` を選んでいく作業は、調べるコミットがなくなるまで続きます。
終了したら、コマンドラインには問題をきたしている**最初の**コミットの詳細が表示されます。
2020-02-13 09:13:04 +06:00
2020-02-22 15:48:48 +06:00
## 設定
2020-02-13 09:13:04 +06:00
2020-02-22 15:48:48 +06:00
### Git コマンドにエイリアスを設定したい
2020-02-13 09:13:04 +06:00
2020-02-22 15:48:48 +06:00
OS X と Linux では、Git 設定ファイルは ```~/.gitconfig``` に保存されています。
私は、ショートカット(とよくやるタイポ)のために次のようなものを ```[alias]``` セクションに設定しています:
2020-02-13 09:13:04 +06:00
```vim
[alias]
a = add
amend = commit --amend
c = commit
ca = commit --amend
ci = commit -a
co = checkout
d = diff
dc = diff --changed
ds = diff --staged
extend = commit --amend -C HEAD
f = fetch
loll = log --graph --decorate --pretty=oneline --abbrev-commit
m = merge
one = log --pretty=oneline
outstanding = rebase -i @{u}
reword = commit --amend --only
s = status
unpushed = log @{u}
wc = whatchanged
wip = rebase -i @{u}
zap = fetch -p
day = log --reverse --no-merges --branches=* --date=local --since=midnight --author=\"$(git config --get user.name)\"
delete-merged-branches = "!f() { git checkout --quiet master && git branch --merged | grep --invert-match '\\*' | xargs -n 1 git branch --delete; git checkout --quiet @{-1}; }; f"
```
2020-02-22 15:48:48 +06:00
### 空のディレクトリをリポジトリに加えたい
2020-02-13 09:13:04 +06:00
2020-02-22 15:48:48 +06:00
できません Git ではできませんが、ハックする方法があります。
次のような内容の .gitignore ファイルを作成してディレクトリに加えればよいです:
2020-02-13 09:13:04 +06:00
```
# Ignore everything in this directory
*
# Except this file
!.gitignore
```
2020-02-22 15:48:48 +06:00
もう一つのよくある方法は、.gitkeep という名前の空のファイルをフォルダーに作成することです。
2020-02-13 09:13:04 +06:00
```sh
$ mkdir mydir
$ touch mydir/.gitkeep
```
2020-02-22 15:48:48 +06:00
単に .keep という名前でもよいです。この場合、二行目は ```touch mydir/.keep``` とします。
2020-02-13 09:13:04 +06:00
2020-02-22 15:48:48 +06:00
### リポジトリへのユーザ名とパスワードをキャッシュしたい
2020-02-13 09:13:04 +06:00
2020-02-22 15:48:48 +06:00
認証が必要なリポジトリがあるとします。ユーザ名とパスワードをキャッシュしておけば、プッシュやプルのたびに入力せずに済みます。
認証情報ヘルパーが役に立ちます。
2020-02-13 09:13:04 +06:00
```sh
$ git config --global credential.helper cache
2020-02-22 15:48:48 +06:00
# Git が認証情報キャッシュを使うよう設定する
2020-02-13 09:13:04 +06:00
```
```sh
$ git config --global credential.helper 'cache --timeout=3600'
2020-02-22 15:48:48 +06:00
# キャッシュが一時間でタイムアウトするよう設定する(設定は秒単位)
2020-02-13 09:13:04 +06:00
```
2020-02-22 15:48:48 +06:00
認証情報ヘルパーを見つけるには:
2020-02-13 09:13:04 +06:00
```sh
$ git help -a | grep credential
2020-02-22 15:48:48 +06:00
# 認証情報ヘルパーの候補が表示される
2020-02-13 09:13:04 +06:00
```
2020-02-22 15:48:48 +06:00
OS 固有の認証情報キャッシュは次の通り:
2020-02-13 09:13:04 +06:00
```sh
$ git config --global credential.helper osxkeychain
2020-02-22 15:48:48 +06:00
# OSX
2020-02-13 09:13:04 +06:00
```
```sh
$ git config --global credential.helper manager
# Git for Windows 2.7.3+
```
```sh
$ git config --global credential.helper gnome-keyring
2020-02-22 15:48:48 +06:00
# Ubuntu やその他の GNOME ベースディストリビューション
2020-02-13 09:13:04 +06:00
```
2020-02-22 15:48:48 +06:00
その他のディストリビューションや OS 向けの認証情報キャッシュもあります。
2020-02-13 09:13:04 +06:00
2020-02-22 15:48:48 +06:00
### パーミッションとファイルモードの変更を Git が無視するようにしたい
2020-02-13 09:13:04 +06:00
```sh
$ git config core.fileMode false
```
2020-02-22 15:48:48 +06:00
これをログインユーザ向けのデフォルト設定にしたい場合、次を実行します。
2020-02-13 09:13:04 +06:00
```sh
$ git config --global core.fileMode false
```
2020-02-22 15:48:48 +06:00
### グローバルユーザを設定したい
2020-02-13 09:13:04 +06:00
2020-02-22 15:48:48 +06:00
全てのローカルリポジトリにわたるユーザ情報を設定し、バージョン履歴のレビューの際にわかりやすい名前を設定するには、次のようにします:
2020-02-13 09:13:04 +06:00
```sh
$ git config --global user.name “[firstname lastname]”
```
2020-02-22 15:48:48 +06:00
各履歴のマーカーに紐づけられるメールアドレスを設定したい場合は次の通りです:
2020-02-13 09:13:04 +06:00
```sh
git config --global user.email “[valid-email]”
```
2020-02-22 15:48:48 +06:00
### Git のコマンドラインに色をつけたい
2020-02-13 09:13:04 +06:00
2020-02-22 15:48:48 +06:00
レビューの際に見やすいようコマンドラインに自動的に色を付けるには、次のようにします:
2020-02-13 09:13:04 +06:00
```sh
$ git config --global color.ui auto
```
## 何を間違ったかわからないとき
2020-02-13 09:13:04 +06:00
何かやらかした場合です。つまり、何かを `reset` してしまった、間違ったブランチをマージしてしまった、あるいは強制プッシュしてしまいコミットが見つけられない、といった状況です。ある時点まではうまくいっていたので、その状態に戻したいとします。
2020-02-13 09:13:04 +06:00
こうしたときに `git reflog` が役に立ちます。`reflog` は、ブランチが他のブランチやタグに参照されていなくても、ブランチになされた変更を記録しています。HEAD が変更される際は基本的に reflog に記録が追加されます。ただ、残念ながら機能するのはローカルリポジトリのみで、変化だけを記録します(たとえば、どこにも記録されていないファイルへの変更は記録されません)。
2020-02-13 09:13:04 +06:00
```sh
(master)$ git reflog
0a2e358 HEAD@{0}: reset: moving to HEAD~2
0254ea7 HEAD@{1}: checkout: moving from 2.2 to master
c10f740 HEAD@{2}: checkout: moving from master to 2.2
```
上の reflog には、master から 2.2 へのチェックアウトが表示されています。
それから古いコミットへの hard reset があります。
最新のアクティビティは一番上に `HEAD@{0}` のラベルで表示されます。
2020-02-13 09:13:04 +06:00
間違えて差し戻ししてしまったとします。
コミット二つを間違って捨ててしまう前の、0254ea7 を参照するコミットを reflog は保持しています。
2020-02-13 09:13:04 +06:00
```sh
$ git reset --hard 0254ea7
```
Using `git reset` it is then possible to change master back to the commit it was before. This provides a safety net in case history was accidentally changed.
`git reset` を使って、マスターブランチを以前の状態に戻すことができます。履歴を間違えて変更してしまった場合の安全策です。
[出典](https://www.atlassian.com/git/tutorials/rewriting-history/git-reflog) からコピー・改変しました。)
2020-02-13 09:13:04 +06:00
<a name="git-shortcuts"></a>
2020-02-22 16:53:18 +06:00
## Git ショートカット
2020-02-13 09:13:04 +06:00
### Git Bash
2020-02-22 16:53:18 +06:00
上記のコマンドに慣れてきたら、Git Bash のショートカットを作りたくなるはずです。複雑なタスクを短いコマンドで素早く行うことができるようになります。
2020-02-13 09:13:04 +06:00
```sh
alias sq=squash
function squash() {
git rebase -i HEAD~$1
}
```
2020-02-22 16:53:18 +06:00
このコマンドを .bashrc か .bash_profile にコピーしてください。
2020-02-13 09:13:04 +06:00
2020-02-22 16:53:18 +06:00
### Windows の PowerShell
2020-02-13 09:13:04 +06:00
2020-02-22 16:53:18 +06:00
Windows で PowerShell を使っているなら、エイリアスや関数を作成できます。profile に次のコマンドを追加してください。profile のパスは `$profile` に定義されています。詳しくは Microsoft のドキュメントサイトの [About Profiles](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_profiles) を参照してください。
2020-02-13 09:13:04 +06:00
```powershell
Set-Alias sq Squash-Commits
function Squash-Commits {
git rebase -i HEAD~$1
}
```
2020-02-22 17:28:09 +06:00
# 文献
2020-02-13 09:13:04 +06:00
2020-02-22 17:28:09 +06:00
## 本
2020-02-13 09:13:04 +06:00
2020-02-22 17:28:09 +06:00
* [Learn Enough Git to Be Dangerous](https://www.learnenough.com/git-tutorial) - Git の基礎からカバーした Michael Hartl の本
* [Pro Git](https://git-scm.com/book/en/v2) - Scott Chacon と Ben Straub による Git に関する素晴らしい本
* [Git Internals](https://github.com/pluralsight/git-internals-pdf) - Scott Chacon による Git に関する素晴らしい本
2020-02-13 09:13:04 +06:00
* [Nasa handbook](https://www.nasa.gov/sites/default/files/atoms/files/nasa_systems_engineering_handbook.pdf)
2020-02-22 17:28:09 +06:00
## チュートリアル
2020-02-13 09:13:04 +06:00
2020-02-22 17:28:09 +06:00
* [19 Git Tips For Everyday Use](https://www.alexkras.com/19-git-tips-for-everyday-use) - Git の便利なワンライナーの一覧
* [Atlassian's Git tutorial](https://www.atlassian.com/git/tutorials) - 初心者から上級者までチュートリアルで Git を正しく使おう
* [Learn Git branching](https://learngitbranching.js.org/) - web で動くブランチ・マージ・リベースの対話的なチュートリアル
2020-02-13 09:13:04 +06:00
* [Getting solid at Git rebase vs. merge](https://medium.com/@porteneuve/getting-solid-at-git-rebase-vs-merge-4fa1a48c53aa)
2020-02-22 17:28:09 +06:00
* [Git Commands and Best Practices Cheat Sheet](https://zeroturnaround.com/rebellabs/git-commands-and-best-practices-cheat-sheet) - ブログ投稿にあるもっと説明の多い Git チートシート
* [Git from the inside out](https://codewords.recurse.com/issues/two/git-from-the-inside-out) - Git の内部に踏み込んだチュートリアル
* [git-workflow](https://github.com/asmeurer/git-workflow) - Git を使ってオープンソースリポジトリに貢献する方法についての [Aaron Meurer](https://github.com/asmeurer) による解説
* [GitHub as a workflow](https://hugogiraudel.com/2015/08/13/github-as-a-workflow/) - GitHub を、特に空のプルリクエストを用いてワークフローとして使う面白い試み
* [Githug](https://github.com/Gazler/githug) - よく使う Git ワークフローを学ぶゲーム
* [learnGitBranching](https://github.com/pcottle/learnGitBranching) - 刺激を得たり教育に使える git の可視化
## スクリプトとツール
* [firstaidgit.io](http://firstaidgit.io/) - 検索可能な Git のよくある質問集
* [git-extra-commands](https://github.com/unixorn/git-extra-commands) - 便利な Git スクリプトのコレクション
* [git-extras](https://github.com/tj/git-extras) - Git の 便利機能 -- リポジトリの要約、REPL、編集履歴の人口、開発者ごとのコミット率など
* [git-fire](https://github.com/qw3rtman/git-fire) - git-fire は緊急時に(マージのコンフリクトを防ぐため)新しいブランチに全ファイルを追加・コミット・プッシュする Git のプラグインです
* [git-tips](https://github.com/git-tips/tips) - ちょっとした Git のコツ
* [git-town](https://github.com/Originate/git-town) - 一般的でハイレベルな Git ワークフローのサポート http://www.git-town.com
## GUI クライアント
* [GitKraken](https://www.gitkraken.com/) - Windows, Mac, Linux で動く真正で豪華な Git クライアント
* [git-cola](https://git-cola.github.io/) - Windows と OS X で動くもう一つの Git クライアント
* [GitUp](https://github.com/git-up/GitUp) - Git の問題に対処する志向の強い方法をそなえた新しい GUI クライアント
* [gitx-dev](https://rowanj.github.io/gitx/) - OS X で動くグラフィカル Git クライアント
* [Sourcetree](https://www.sourcetreeapp.com/) - シンプルさと強力さを兼ね備えた美しい無料の Git GUI です。Windows と Mac で動きます。
* [Tower](https://www.git-tower.com/) - OS X で動くグラフィカル Git クライアント(有料)
* [tig](https://jonas.github.io/tig/) - Git のターミナルテキストモードインターフェース
* [Magit](https://magit.vc/) - Emacs のパッケージとして実装された Git のインターフェース
* [GitExtensions](https://github.com/gitextensions/gitextensions) - シェル拡張・Visual Studio 2010-2015 プラグイン・スタンドアローンの Git リポジトリツール
* [Fork](https://git-fork.com/) - Mac で動く高速で使いやすい Git クライアント(ベータ版)
* [gmaster](https://gmaster.io/) - Windows で動く、三者間マージ、リファクタリング解析、セマンティック差分とマージのできる Git クライアント(ベータ版)
* [gitk](https://git-scm.com/docs/gitk) - Linux で動くリポジトリの状態をシンプルに見られる Git クライアント
* [SublimeMerge](https://www.sublimemerge.com/) - 三者間マージ・強力な検索機能・シンタックスハイライトをそなえた驚異的に高速で拡張性の高いクライアント。活発に開発されている