Git 基本(プッシュ・クローン・プル・マージ)

リモートリポジトリにプッシュ

リモートリポジトリにプッシュする|サル先生のGit入門【プロジェクト管理ツールBacklog】

実際にリモートリポジトリにローカルリポジトリの履歴をpushする前に

リモートリポジトリのアドレスに名前を付けて登録しておく

  • リモートリポジトリのアドレス (URL) は名前を付けて記録しておくことができる
    • 記録しておくと、pushするときには毎回長いリモートリポジトリのアドレスを入力する必要がなくなる
  • リモートリポジトリを追加するには、remote コマンドを使用する
    • % remote add <name> <url>
      • nameは登録名、urlはリモートリポジトリのURLを指定
  • まずは「origin」という名前でリモートリポジトリを登録してからpushを行ってみる
    • * プッシュやプルは実行時にリモートリポジトリ名を省略すると、originという名前のリモートリポジトリを使用する
    • そのため、リモートリポジトリにはoriginという名前を付けるのが一般的
% git remote add origin https://github.com/htksn-git/testgit.git

リポジトリをプッシュする

  • リポジトリをプッシュするには、pushコマンドを使用する
    • repositoryはプッシュ先のアドレス、refspecはプッシュするブランチを指定する
  • % git push <repository> <refspec>...
  • 次のコマンドを実行してリモートリポジトリoriginにコミットをpushする
    • 実行オプションで -u を指定すると、次回以降はそのブランチ名の指定を省略できる
    • ただし、空のリモートリポジトリに初めて push するときはリモートリポジトリ名やブランチ名を省略できない
% git push -u origin master
  • GitHub 上にローカルリポジトリの内容がプッシュされたことを確認

リモートリポジトリをクローン

リモートリポジトリをクローンする|サル先生のGit入門【プロジェクト管理ツールBacklog】

  • リポジトリを複製するにはcloneコマンドを使用する
  • repositoryはリモートリポジトリのURL、directoryは複製先のディレクトリ名を指定する
  • % git clone <repository> <directory>
% git clone https://github.com/htksn-git/testgit.git testgit_copy
  • コマンドを実行すると、カレントディレクトリに testgit_copy という名前のディレクトリ名でリモートリポジトリが複製される
% git clone https://github.com/htksn-git/testgit.git testgit_copy
Cloning into 'testgit_copy'...
remote: Enumerating objects: 21, done.
remote: Counting objects: 100% (21/21), done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 21 (delta 0), reused 21 (delta 0), pack-reused 0
Receiving objects: 100% (21/21), done.

% ls
hello.txt   test.txt    testgit_copy
  • 中身を確認してみる
% cat testgit_copy/test.txt
content of test
haha
wow
hoho

クローンしたリポジトリからプッシュ

クローンしたリポジトリからプッシュする|サル先生のGit入門【プロジェクト管理ツールBacklog】

  • クローンしたリポジトリのファイルに変更を加える
% cd testgit_copy
% vim testgit_copy/test.txt
% cat testgit_copy/test.txt
content of test
haha
wow
hoho

this is clone
  • コミットする
% git add .
% git commit -m "クローンしたファイルに追記"
[master 70e2e17] クローンしたファイルに追記
 1 file changed, 2 insertions(+)
  • 変更をプッシュしてリモートリポジトリを更新する
    • クローンしたリポジトリでは、pushのパラメータのorigin masterは省略できる
% git push
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 8 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 357 bytes | 357.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
To https://github.com/htksn-git/testgit.git
   2a36d99..70e2e17  master -> master
  • GitHub を確認したら、プッシュしたコミットが追加されていた

リモートリポジトリからプル

リモートリポジトリからプルする|サル先生のGit入門【プロジェクト管理ツールBacklog】

  • プルする前のファイルの中身を確認
% cd ../
% cat test.txt
content of test
haha
wow
hoho
  • リモートリポジトリからプル
% git pull origin master
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 3 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), 337 bytes | 168.00 KiB/s, done.
From https://github.com/htksn-git/testgit
 * branch            master     -> FETCH_HEAD
   2a36d99..70e2e17  master     -> origin/master
Updating 2a36d99..70e2e17
Fast-forward
 test.txt | 2 ++
 1 file changed, 2 insertions(+)
  • ログを確認
% git log
commit 70e2e17d7db45924e224c01e1fcd192e782c6baf (HEAD -> master, origin/master)
Author: htksn <hoge@gmail.com>
Date:   Sun Sep 11 17:53:05 2022 +0900

    クローンしたファイルに追記

commit 2a36d990a37bfc66a3ec633a76bcafab23fab86a
Author: htksn <hoge@gmail.com>
Date:   Sun Sep 11 16:38:39 2022 +0900

    second commit
  • ファイルの中身も変更されていた
% cat test.txt
content of test
haha
wow
hoho

this is clone

変更履歴のマージ

変更履歴のマージ|サル先生のGit入門【プロジェクト管理ツールBacklog】

  • 最後にpullを実行してから次のpushをするまでの間に、ほかの人がpushをしてリモートリポジトリを更新してしまっていた場合には、自分のpushが拒否される
  • この場合、マージという作業を行なって他の履歴での変更を取り込むまで自分のpushは拒否される
    • マージを行わないまま履歴を上書きしてしまうと、ほかの人がpushした変更が失われてしまうため
  • マージでは、Gitが変更箇所を自動的に統合してくれる
    • ただし、自動では統合出来ない場合もある
      • この場合は手動で統合する必要がある

マージ時の競合の解決

競合の解決|サル先生のGit入門【プロジェクト管理ツールBacklog】

  • リモートリポジトリとローカルリポジトリでファイル内の同じ箇所を変更していると、マージによって自動で統合することはできない
    • どちらの変更を取り込むか自動では判断できないのでエラーが発生する
  • 競合が発生した箇所は、Gitがファイルの内容を次の図のように修正するので、手動で修正する必要がある
    • == で区切られた上側がローカルリポジトリ、下側がリモートリポジトリの編集内容

  • 次の図のように、すべての競合箇所を修正してから、コミットを行うと変更を統合したコミットが作成される

競合状態でプッシュする

競合状態でプッシュする|サル先生のGit入門【プロジェクト管理ツールBacklog】

  • はじめに、基準とするファイルに追記し、コミットする
22-09-11 ~/testgit % vim test.txt
22-09-11 ~/testgit % cat test.txt
content of test
haha
wow
hoho

this is clone

hogehogehoge
22-09-11 ~/testgit % ga # add
22-09-11 ~/testgit % cm="競合状態を作り出す"
22-09-11 ~/testgit % gc # commit
[master c2428b6] 競合状態を作り出す
 2 files changed, 3 insertions(+)
 create mode 160000 testgit_copy
  • 次に、クローンしたファイルに追記し、コミットする
22-09-11 ~/testgit % cd testgit_copy
22-09-11 ~/testgit/testgit_copy % vim test.txt
22-09-11 ~/testgit/testgit_copy % cat test.txt
content of test
haha
wow
hoho

this is clone

fugafugafuga
22-09-11 ~/testgit/testgit_copy % ga
22-09-11 ~/testgit/testgit_copy % cm="競合状態を作り出す ver.2"
22-09-11 ~/testgit/testgit_copy % gc
[master 9d350a3] 競合状態を作り出す ver.2
 1 file changed, 2 insertions(+)
  • そのままクローンしたファイルをプッシュする
22-09-11 ~/testgit/testgit_copy % git push
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 8 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 360 bytes | 360.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
To https://github.com/htksn-git/testgit.git
   70e2e17..9d350a3  master -> master
  • 続いて、基準とするファイルをプッシュする
22-09-11 ~/testgit/testgit_copy % ..
22-09-11 ~/testgit % git push
To https://github.com/htksn-git/testgit.git
 ! [rejected]        master -> master (fetch first)
error: failed to push some refs to 'https://github.com/htksn-git/testgit.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
  • エラーが表示され、プッシュできない

競合を解決する

競合を解決する|サル先生のGit入門【プロジェクト管理ツールBacklog】

  • 競合を手動で解決するため、リモートリポジトリからプルしてくる
  • エラーが出る
  • しかし、エラー文を読んでいると git config をどうにかしろ的な内容であり、『サル先生のGitコマンド入門』に書かれているマージ中に競合が発生したことを表すメッセージではなさそう
    • Need to specify how to reconcile divergent branches.
    • 「分岐したブランチをどのように解決するか指定せよ」
22-09-11 ~/testgit % git pull origin master
From https://github.com/htksn-git/testgit
 * branch            master     -> FETCH_HEAD
hint: You have divergent branches and need to specify how to reconcile them.
hint: You can do so by running one of the following commands sometime before
hint: your next pull:
hint:
hint:   git config pull.rebase false  # merge
hint:   git config pull.rebase true   # rebase
hint:   git config pull.ff only       # fast-forward only
hint:
hint: You can replace "git config" with "git config --global" to set a default
hint: preference for all repositories. You can also pass --rebase, --no-rebase,
hint: or --ff-only on the command line to override the configured default per
hint: invocation.
fatal: Need to specify how to reconcile divergent branches.

特に、今までの動作に不満がないという人は git config --global pull.rebase false をやっておけば、今までの挙動の通り、 warning だけ出なくなります。

  • とりあえず git config --global pull.rebase false で進めることにする
    • 「設定をどうするか」といった内容なので、不都合があればまた変えればいい

~ 気を取り直して作業再開 ~

  • 競合を手動で解決するため、リモートリポジトリからプルしてくる
  • 今度はさっきと異なるエラーが出る
    • 意図した通りの「マージ中に競合が発生したことを表すメッセージ」
22-09-11 ~/testgit % git pull origin master
From https://github.com/htksn-git/testgit
 * branch            master     -> FETCH_HEAD
Auto-merging test.txt
CONFLICT (content): Merge conflict in test.txt
Automatic merge failed; fix conflicts and then commit the result.
  • Merge conflict in test.txt と書いてあるので調べる
22-09-11 ~/testgit % cat test.txt
content of test
haha
wow
hoho

this is clone

<<<<<<< HEAD
hogehogehoge
=======
fugafugafuga
>>>>>>> 9d350a3d39722344ede210333423586d42c4013e
  • 両方の変更を取り入れることにして、余計なマーカ行は削除
22-09-11 ~/testgit % vim test.txt
22-09-11 ~/testgit % cat test.txt
content of test
haha
wow
hoho

this is clone

hogehogehoge
fugafugafuga
  • ファイルの内容をコミット
22-09-11 ~/testgit % ga
22-09-11 ~/testgit % cm="競合を手動で解決"
22-09-11 ~/testgit % gc
[master 46c62a6] 競合を手動で解決
  • git log --graph --oneline
    • logコマンドで履歴を確認
      • --graph オプションを指定するとテキストで履歴の流れを表示することができる
      • --oneline オプションを指定するとコミットの情報を一行で表示できる
22-09-11 ~/testgit % git log --graph --oneline
*   46c62a6 (HEAD -> master) 競合を手動で解決
|\
| * 9d350a3 (origin/master) 競合状態を作り出す ver.2
* | c2428b6 競合状態を作り出す
|/
* 70e2e17 クローンしたファイルに追記
* 2a36d99 second commit
* 103a4bb first commit
  • 二つの変更を統合したことが確認できたので、改めてプッシュする
22-09-11 ~/testgit % git push
Enumerating objects: 10, done.
Counting objects: 100% (10/10), done.
Delta compression using up to 8 threads
Compressing objects: 100% (6/6), done.
Writing objects: 100% (6/6), 734 bytes | 734.00 KiB/s, done.
Total 6 (delta 1), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (1/1), done.
To https://github.com/htksn-git/testgit.git
   9d350a3..46c62a6  master -> master
  • GitHub でも無事に反映されていることが確認できた