web-dev-qa-db-ja.com

git branch、fork、fetch、merge、rebase、cloneの違いは何ですか?

Gitのブランチ、フォーク、クローンの違いを理解したいのですが。

同様に、git fetchとは対照的にgit pullを実行するとどうなりますか?

また、rebasemergeと比較してどういう意味ですか?

個々のコミットをまとめて潰すことができますか。

彼らはどのように使われているのか、なぜ使われているのか、そして何を表しているのか?

GitHubはどのように組み込まれているのですか?

487
jackiekazil

クローンは単にリポジトリのコピーです。表面的には、その結果はsvn checkoutと同等です。ここで、他のリポジトリからソースコードをダウンロードします。 Subversionのような一元化されたVCSとGitのようなDVCSの違いは、Gitでは、クローンを作成するときに、実際にはすべての履歴とブランチを含むソースリポジトリ全体をコピーしているということです。これであなたはあなたのマシンに新しいリポジトリを作成し、あなたが行ったコミットはそのリポジトリに入ります。公にアクセス可能であれば、コミットを別のリポジトリ(または元のリポジトリ)にプッシュするか、誰かがコミットをコミットするまで、誰も変更を確認できません。

ブランチはリポジトリ内にあるものです。概念的には、それは開発のスレッドを表します。あなたは通常masterブランチを持っていますが、xyzやバグabcを修正するためにもう1つの機能に取り組んでいるブランチもあるかもしれません。ブランチをチェックアウトすると、コミットはそのブランチに残り、他のブランチとマージするか、問題のブランチにリベースするまで共有されません。もちろん、Gitは、ブランチがどのように実装されているかの基礎となるモデルを見るまで、ブランチに関してはちょっと変に思えます。それを自分で説明するのではなく(私がすでにあまりにも多く言ってしまったように、私は考えます)、GitのWebサイトから抜粋した、Gitモデルの分岐とコミットの仕方に関する「コンピュータサイエンス」の説明にリンクします。

http://eagain.net/articles/git-for-computer-scientists/

フォークはGitの概念ではなく、政治的/社会的な概念です。つまり、プロジェクトの進行状況に満足できない人がいる場合は、元の開発者とは別にソースコードを受け取って作業することができます。それはフォークと見なされます。 Gitは、誰もが自分自身のソースコードの「マスター」コピーをすでに持っているので、フォークを簡単にします。そのため、元のプロジェクト開発者との結びつきを減らすのと同じくらい簡単です。SVNのように共有リポジトリから履歴をエクスポートする必要はありません。 。

編集:私はGitHubのようなサイトで使用されているような "フォーク"の現代の定義を知らなかったので、コメントを見てくださいまた詳細については私の下の マイケルデュラントの答え

359
siride

Git

この回答には、多くの人々がそれについても質問しているように、GitHubが含まれています。

ローカルリポジトリ

Git(ローカル)には、ファイルをコミットするディレクトリ(.git)があり、これが「ローカルリポジトリ」です。これは、リモートリポジトリにすぐに追加してコミットするSVNなどのシステムとは異なります。

Gitは、ファイル全体を保存することで変更されるファイルの各バージョンを保存します。また、デルタの変更によって「再作成」せずに個々のバージョンに移動できるため、この点でもSVNとは異なります。

Gitはファイルをまったく「ロック」せず、編集の「排他的ロック」機能を回避します(PVCのような古いシステムが頭に浮かぶため)、オフラインでもすべてのファイルを常に編集できます。実際には、GitHubなどのリモートリポジトリへのプルまたはフェッチ/プッシュ中に、(同じファイル内で)ファイルの変更をマージするという驚くべき仕事をします。手動で変更(実際にファイルを編集)する必要があるのは、2つの変更に同じコード行が関係している場合だけです。


ブランチを使用すると、メインコード(「マスター」ブランチ)を保持し、コピー(新しいブランチ)を作成して、その新しいブランチ内で作業できます。作業に時間がかかる場合、またはブランチが作成されてからマスターが多くの更新を取得した場合、マスターブランチに対するマージまたはリベース(多くの場合、より良い履歴と競合の解決が容易なため)を行う必要があります。終了したら、ブランチで行った変更をマスターリポジトリにマージします。多くの組織では、機能、バグ、または雑用アイテムに関係なく、作業ごとにブランチを使用しています。他の組織では、バージョンアップグレードなどの主要な変更にのみブランチを使用しています。

分岐:分岐では分岐を制御および管理しますが、分岐では他の誰かがコードの受け入れを制御します。

大まかに言えば、分岐を行うには2つの主なアプローチがあります。 1つ目は、マスターブランチでほとんどの変更を保持することです。バージョンの変更のように、異なるニーズに応じて2つのブランチを使用できるようにする、より大きく長時間実行するブランチのみを使用します。 2つ目は、基本的に、すべての機能要求、バグ修正、または雑用ごとにブランチを作成し、それらのブランチを実際にメインマスターブランチにマージするタイミングを手動で決定することです。これは退屈に聞こえますが、これは一般的なアプローチであり、マスターブランチをよりクリーンに保ち、プロダクションに昇格させるマスターであるため、現在使用および推奨しているアプローチです。ブランチのマージ。

ブランチをマスターに「取り込む」ための標準的な方法は、mergeを実行することです。ブランチは、履歴を「クリーンアップ」するために「リベース」することもできます。現在の状態には影響せず、「よりクリーンな」履歴を提供するために行われます。

基本的には、特定のポイント(通常はマスター)から分岐するという考え方です。あなたが分岐したので、「マスター」自体はその分岐点から前進しました。ブランチで行ったすべての変更が、すべての最新の変更を含む現在のマスターの状態に対して実行される場合、「クリーン」になります(問題の解決が容易になり、履歴が理解しやすくなります)。そのため、プロセスは次のとおりです。変更を保存します。 「新しい」マスターを取得してから、その変更を再度適用します(これがリベース部分です)。マージと同様に、リベースは競合を引き起こす可能性があることに注意してください。競合は手動で解決する必要があります(つまり、編集と修正)。

注意すべき1つのガイドライン:
ブランチがローカルで、まだリモートにプッシュしていない場合のみリベースします!
これは主に、リベースにより、他の人が見る履歴に変更を加えることができるためです。

追跡ブランチ

これらは、Origin/branch_nameという名前のブランチです(単にbranch_nameとは対照的です)。コードをリモートリポジトリにプッシュしたり、リモートリポジトリからプルしたりするとき、これが実際にそれが起こるメカニズムです。たとえば、git Pushというブランチをbuilding_groupsという名前にすると、ブランチは最初にOrigin/building_groupsに移動し、次にリモートリポジトリに移動します。同様に、git fetch building_groupsを実行すると、取得されたファイルはOrigin/building_groupsブランチに配置されます。その後、このブランチをローカルコピーにマージすることを選択できます。私たちのプラクティスは、git fetch(上記の両方を1ステップで行う)ではなく、常にgit pullと手動マージを行うことです。

新しいブランチを取得しています。

新しいブランチの取得:クローンの最初の時点では、すべてのブランチがあります。ただし、他の開発者がブランチを追加してリモートにプッシュする場合、それらをローカルにプルダウンできるようにするために、それらのブランチとその名前を「知る」方法が必要です。これは、git fetchを介して行われます。これは、追跡ブランチを使用して、すべての新規および変更されたブランチをローカルリポジトリに取得します(例:Origin/)。 fetchedになったら、git branch --remoteで追跡ブランチをリストし、git checkout [branch]で実際に任意のブランチに切り替えることができます。

マージ

マージとは、異なるブランチまたは同じブランチの異なるバージョンからのコード変更を結合するプロセスです(たとえば、ローカルブランチとリモートが同期していない場合)。ブランチで作業を開発し、作業が完了し、準備ができてテストされている場合、それをmasterブランチにマージできます。これはgit checkout masterによって行われ、masterブランチに切り替えてからgit merge your_branchに切り替えます。マージにより、すべての異なるファイルと同じファイルに対する異なる変更がまとめられます。これは、ファイル内のコードを実際に変更して、すべての変更をマージすることを意味します。

checkoutmasterを実行するときは、git pull Origin masterを実行して、最新バージョンのリモートマスターをローカルマスターにマージすることもお勧めします。リモートマスターが変更された場合、つまりmoved forwardの場合、そのgit pullの間にそれを反映する情報が表示されます。その場合(マスターが変更された場合)、マスターにgit checkout your_branchしてからrebaseすることをお勧めします。これにより、変更が実際に「新しい」マスターの上で「リプレイ」されます。次に、次の段落に示すように、マスターを最新の状態に保ちます。

競合がない場合、マスターは新しい変更を追加します。競合がある場合、これは同じファイルが自動的にマージできない同様のコード行の周りに変更があることを意味します。この場合、git merge new_branchは、解決すべき競合があることを報告します。ファイル(両方の変更が含まれる)を編集し、必要な変更を選択し、不要な変更の行を文字通り削除してからファイルを保存することにより、それらを「解決」します。変更には、========<<<<<<<<などの区切り記号が付いています。

競合を解決したら、git addgit commitの変更をもう一度実行して、マージを続行します(このプロセス中にgitからフィードバックが得られます)。

プロセスがうまく機能しない場合、git merge --abortがリセットに非常に便利であることがわかります。

インタラクティブなリベースとスカッシュ/リオーダー/コミットの削除

たとえば、毎日「進行中の作業」としてコードをコミットするなど、多くの小さなステップで作業を行った場合、それらの多くの小さなコミットをいくつかの大きなコミットに「押しつぶす」ことができます。これは、同僚とコードレビューを行いたい場合に特に役立ちます。 (コミットを介して)行ったすべての「ステップ」を再生したくはありません。ここで、この作業に対するすべての変更の最終的な効果(diff)を1つのコミットで言いたいだけです。

これを行うかどうかを検討する際に評価する重要な要素は、複数のコミットが同じファイルまたは複数のファイルに対するものであるかどうかです(その場合、コミットを無効にする)。これは、インタラクティブなリベースツールを使用して行われます。このツールを使用すると、コミットのスカッシュ、コミットの削除、メッセージの書き換えなどを行うことができます。たとえば、git rebase -i HEAD~10注:~ではなく-です)次を表示します:

interactive rebasing in Git

ただし、このツールは「生々しく」使用してください。一度に1つのスカッシュ/削除/並べ替えを行い、終了してそのコミットを保存してから、ツールを再入力してください。コミットが連続していない場合は、順序を変更できます(必要に応じてスカッシュします)。ここで実際にコミットを削除することもできますが、それを行うときには、実際に何をしているかを確認する必要があります!

フォーク

Gitリポジトリでのコラボレーションには、主に2つのアプローチがあります。上記の詳細な最初の方法は、人々がプルしたりプッシュしたりするブランチを介して直接行われます。これらの共同作業者は、リモートリポジトリにSSHキーを登録しています。これにより、そのリポジトリに直接プッシュできるようになります。欠点は、ユーザーのリストを維持する必要があることです。他のアプローチ-フォーク-誰でもリポジトリを「フォーク」できます。基本的に、自分のGitリポジトリアカウントにローカルコピーを作成します。その後、変更を加えて、「プルリクエスト」(実際には、それらからの「プッシュ」と実際のリポジトリメンテナーに対する「プル」リクエスト)を送信して、コードを受け入れます。

フォークを使用するこの2番目の方法では、notはリポジトリのユーザーのリストを管理する必要があります。


GitHub

GitHub(リモートリポジトリ)は、このようなリポジトリを持っている(または追加されている)場合、通常、コミットされた変更をプッシュおよびプルするリモートソースです。したがって、ローカルとリモートは実際にはまったく異なります。リモートリポジトリを考えるもう1つの方法は、リモートサーバー上にある.gitディレクトリ構造です。

「フォーク」すると、GitHub WebブラウザーGUIでこのボタンをクリックできます Image of fork button -yourGitHubアカウントにコードのコピー(「クローン」)を作成します。最初にやるのは少し微妙かもしれませんので、コードベースがリストされているリポジトリを確認してください-元の所有者または「fork from」のいずれかで、次のようになります:

Image of name of forked repository

ローカルコピーを取得したら、必要に応じて変更を行うことができます(ローカルマシンにプルアンドプッシュすることにより)。完了したら、元のリポジトリの所有者/管理者に「プルリクエスト」を送信します(派手に聞こえますが、実際にはこれをクリックするだけです: Image of pull request button)そして、彼らはそれを「プル」します。

コードを一緒に作業するチームにとってより一般的なのは、リポジトリの「クローン」です(リポジトリのメイン画面の「コピー」アイコンをクリックします)。次に、ローカルでgit cloneと入力して貼り付けます。これにより、ローカルにセットアップされ、(共有)GitHubロケーションにプッシュおよびプルすることもできます。

クローン

GitHubのセクションで示したように、クローンはリポジトリのコピーです。リモートリポジトリがある場合、そのURLに対してgit cloneコマンドを発行すると、リポジトリのローカルコピーまたはクローンが作成されます。このクローンには、everything、ファイル、masterブランチ、他のブランチ、既存のすべてのコミット、Shebang全体が含まれます。追加とコミットを行うのはこのクローンであり、リモートリポジトリ自体がこれらのコミットのプッシュ先です。 Git(およびMercurialなどのそれに類似したシステム)をDVCS(Distributedバージョン管理システム)にするのは、このローカル/リモートの概念ですSVN、PVCS、CVSなど、リモートリポジトリに直接コミットする従来のCVS(コードバージョン管理システム)。

可視化

コアコンセプトの視覚化については、
http://marklodato.github.com/visual-git-guide/index-en.html および
http://ndpsoftware.com/git-cheatsheet.html#loc=index

変更がどのように機能しているかを視覚的に表示したい場合は、視覚ツールgitg(macOSの場合はgitx)を、私が「地下鉄マップ」と呼ぶGUI(特にロンドン)で打ち負かすことはできません地下)、誰が何をしたか、物事がどのように変化し、分岐し、合併したかなどを示すのに最適.

また、それを使用して、変更を追加、コミット、および管理することもできます!

Image of gitg/gitx interface

Gitg/gitxはごくわずかですが、GUIツールの数は増え続けています。多くのMacユーザーは、brotherbardのgitxフォークを使用します。Linuxの場合、優れたオプションは、直感的で強力なインターフェースを備えたsmart-gitです。

Image of smart-git GUI

GUIツールを使用しても、コマンドラインで多くのコマンドを実行することに注意してください。

このため、~/.bash_aliasesファイルには次のエイリアスがあります(各ターミナルセッションの~/.bashrcファイルから呼び出されます)。

# git
alias g='git status'
alias gcob='git checkout -b '
alias gcom='git checkout master'
alias Gd='git diff'
alias gf='git fetch'
alias gfrm='git fetch; git reset --hard Origin/master'
alias gg='git grep '
alias gits='alias | grep "^alias g.*git.*$"'
alias gl='git log'
alias gl1='git log --oneline'
alias glf='git log --name-status'
alias glp='git log -p'
alias gpull='git pull '
alias gpush='git Push '

そして、私は~/.gitconfigファイルに以下の「gitエイリアス」を持っています-なぜこれらがあるのですか?
そのため、ブランチ補完(TABキーを使用)が機能します!

これらは次のとおりです。

[alias]
  co = checkout
  cob = checkout -b

使用例:git co [branch] <-ブランチのタブ補完が機能します。

GUI学習ツール

https://learngitbranching.js.org/ は、いくつかの基本概念を学習するのに役立ちます。スクリーンショット: enter image description here
ビデオ: https://youtu.be/23JqqcLPss

最後に、7つの重要なライフセーバー!

  1. 変更を加え、それらを追加してコミットします(ただし、プッシュしないでください)。マスターにいることに気づきます!

    git reset [filename(s)]
    git checkout -b [name_for_a_new_branch]
    git add [file(s)]
    git commit -m "A useful message"
    
    Voila!  You've moved that 'master' commit to its own branch !
    
  2. ローカルブランチで作業しているときにいくつかのファイルを台無しにして、最後にgit pullを実行したときの状態に戻りたい場合:

    git reset --hard Origin/master  # You will need to be comfortable doing this!
    
  3. ローカルで変更を開始し、半ダースのファイルを編集した後、マスター(または別の)ブランチにいます:

    git checkout -b new_branch_name  # just create a new branch
    git add .                      # add the changes files
    git commit -m"your message"    # and commit them
    
  4. 現在のブランチで特定のファイルを台無しにして、そのファイルをリモートリポジトリから最後にプルしたときの状態に基本的に「リセット」(変更を失います)したい場合:

    git checkout your/directories/filename
    

    これにより、実際にファイルがリセットされます(多くのGitコマンドと同様に、ここで実行していることにちなんで名前が付けられていません)。

  5. いくつかの変更をローカルで行い、git resetまたはrebaseを実行している間、それらが失われないようにしたい:プロジェクト全体の手動コピーを作成することが多い(cp -r ../my_project ~/) Gitを台無しにするのか、重要な変更を失うのかわからないとき。

  6. あなたはリベースしていますが、物事は台無しになります:

    git rebase --abort # To abandon interactive rebase and merge issues
    
  7. GitブランチをPS1プロンプトに追加します( https://unix.stackexchange.com/a/127800/1004 を参照)。

    Image of Prompt

    ブランチはSelenium_rspec_conversionです。

520
Michael Durrant

これがOliver Steeleのイメージです。

enter image description here

142
Contango

フォーク対。クローン - 両方ともコピーを意味する2つの単語

この 図を見てください。 (もともと http://www.dataschool.io/content/images/2014/Mar/github1.png から)。

.-------------------------.     1. Fork     .-------------------------.
| Your GitHub repo        | <-------------- | Joe's GitHub repo       |
| github.com/you/coolgame |                 | github.com/joe/coolgame |
| ----------------------- | 7. Pull Request | ----------------------- |
| master -> c224ff7       | --------------> | master -> c224ff7 (c)   |
| anidea -> 884faa1 (a)   |                 | anidea -> 884faa1 (b)   |
'-------------------------'                 '-------------------------'
    |                 ^
    | 2. Clone        |
    |                 |
    |                 |
    |                 |
    |                 |
    |                 | 6. Push (anidea => Origin/anidea)
    v                 |
.-------------------------.
| Your computer           |  3. Create branch 'anidea'
| $HOME/coolgame          |
| ----------------------- |  4. Update a file
| master -> c224ff7       |
| anidea -> 884faa1       |  5. Commit (to 'anidea')
'-------------------------'

(a) - after you have pushed it
(b) - after Joe has accepted it
(c) - eventually Joe might merge 'anidea' (make 'master -> 884faa1')

フォーク

  • それをJoeのものにリンクするあなたのリモートレポ(クラウド)へのコピー
  • コピーしてあなたのローカルレポジトリとF *%$ - upにクローンできます
  • 完了したら、リモコンにプッシュバックできます
  • プルリクエストをクリックして、Joeが自分のプロジェクトでそれを使用するかどうかを尋ねることができます。

クローン

  • あなたの地元のレポ(ハードディスク)へのコピー

他の人に追加するために、フォークに固有の注意事項。

技術的には、リポジトリのクローン作成とリポジトリのフォークは同じことであることを認識しておくのは良いことです。行う:

git clone $some_other_repo

そしてあなたは後ろをタップすることができます---あなたはちょうど他のレポを二分したところです。

Gitは、VCSとして、実際のところすべてです。 クローニング フォークcgitのようなリモートUIを使って「ただブラウズする」こととは別に、関与しないgitリポジトリにはほとんど関係がありません。 フォーク ある時点でレポジトリを複製する。

しかしながら、

  • 誰かが私がリポジトリXをフォークしたと言うとき、彼らは公開することを意図してどこかにリポジトリのクローンを作成したことを意味します。 他の人に、たとえばいくつかの実験を見せるため、または異なるアクセス制御メカニズムを適用するため(たとえば、Githubにアクセスできないが社内のアカウントを持つ人々が共同作業できるようにするため)。

    事実:リポジトリはたぶんgit clone以外のコマンドで作成され、誰かのラップトップとは対照的にサーバー上のどこかにホストされ、そして多少異なるフォーマットを持つ(それは "裸のリポジトリ"、すなわち作業ツリーなし) )すべて技術的な詳細です。

    おそらくそれがブランチ、タグ、またはコミットの異なるセットを含んでいるという事実は、おそらく彼らがそもそもそれをやった理由です。

    (Githubが[fork]をクリックしたときに実行するのは、単に砂糖を追加してクローンを作成することです。リポジトリを複製し、自分のアカウントに配置し、 "fork from"をどこかに記録し、 "upstream"という名前のリモートを追加します。 Niceアニメーションを再生します。)

  • 誰かが私がリポジトリXをクローンしたと言うとき、彼らは意図的にそれを研究して彼らのラップトップまたはデスクトップにローカルにリポジトリのクローンを作成したことを意味します。それに貢献する、あるいはその中のソースコードから何かを構築する。

Gitの長所は、これがすべて完璧にフィットすることです。 ブロック チェインをコミットするので、安全に(下記の注を参照)、必要に応じてこれらすべてのリポジトリ間で変更を前後にマージすることができます。


注:チェーンの共通部分を書き換えない限り、そして変更が矛盾しない限り、「安全に」。

6
Alois Mahdal