ここではリモートリポジトリとしてLocalプロトコルを用います。
ローカルリポジトリはLocalReposディレクトリに、リモートリポジトリはRemoteReposディレクトリで管理するとします。
目次
- 1 リモートサーバーの確認 (git remote -v)
- 2 リモートリポジトリの登録を追加 (git remote add)
- 3 リモートリポジトリの登録を解除 (git remote rm)
- 4 フェッチ。リモートリポジトリの内容をダウンロード (git fetch)
- 5 プッシュ。リモートリポジトリへの記録 (git push)
- 6 プル。フェッチとマージの連続操作 (git pull)
- 7 プル。フェッチとリベースの連続操作 (git pull --rebase)
- 8 リモートリポジトリの名前を表示 (git remote show)
- 9 リモートリポジトリの登録の名前の変更 (git remote rename)
リモートサーバーの確認 (git remote -v)
git remote -vで登録されているリモートサーバーを確認できます。
例えば、リポジトリをクローンするとリモートサーバーとしてクローンするリポジトリが登録されます。
クローンによってデフォルトで登録されるリモートリポジトリの名前はoriginになります。
1 2 3 4 5 6 7 |
~/LocalRepos$ git clone ~/RemoteRepos/TestProject.git && cd TestProject Cloning into 'TestProject'... warning: You appear to have cloned an empty repository. done. ~/LocalRepos/TestProject (master) $ git remote -v origin /home/ubuntu/RemoteRepos/TestProject.git (fetch) origin /home/ubuntu/RemoteRepos/TestProject.git (push) |
リモートリポジトリの登録を追加 (git remote add)
git remote addでリモートリポジトリを登録することもできます。リモートリポジトリを登録する際に名前をつけます。この名前はリモートリポジトリを指定したいときに利用します。
1 2 3 4 5 6 |
~/LocalRepos/TestProject (master) $ git remote add Bob ~/RemoteRepos/TestProject_Bob.git ~/LocalRepos/TestProject (master) $ git remote -v Bob /home/ubuntu/RemoteRepos/TestProject_Bob.git (fetch) Bob /home/ubuntu/RemoteRepos/TestProject_Bob.git (push) origin /home/ubuntu/RemoteRepos/TestProject.git (fetch) origin /home/ubuntu/RemoteRepos/TestProject.git (push) |
リモートリポジトリの登録を解除 (git remote rm)
git remote rmでリモートリポジトリの登録を解除できます。
1 2 3 4 |
~/LocalRepos/TestProject (master) $ git remote rm Bob ~/LocalRepos/TestProject (master) $ git remote -v origin /home/ubuntu/RemoteRepos/TestProject.git (fetch) origin /home/ubuntu/RemoteRepos/TestProject.git (push) |
フェッチ。リモートリポジトリの内容をダウンロード (git fetch)
フェッチすることでリモートリポジトリの内容をダウンロードすることができます。
リモートリポジトリのブランチ名はタグのような感じでリモートリポジトリから情報を更新しない限り、ローカルリポジトリでは変化しません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
~/LocalRepos/TestProject (master) $ git fetch remote: Enumerating objects: 7, done. remote: Counting objects: 100% (7/7), done. remote: Compressing objects: 100% (5/5), done. remote: Total 7 (delta 1), reused 0 (delta 0), pack-reused 0 Unpacking objects: 100% (7/7), 527 bytes | 131.00 KiB/s, done. From /home/ubuntu/RemoteRepos/TestProject * [new branch] master -> origin/master * [new branch] b1 -> origin/b1 ~/LocalRepos/TestProject (master) $ git log --oneline --all --graph --decorate * dfff24b (origin/b1) b1 3 commit | * 3e75d1d (origin/master) 2 commit |/ * 220b89b 1 commit ~/LocalRepos/TestProject (master) $ |
チェックアウト時にリモートリポジトリのリモート追跡ブランチ(例のorigin/masterのこと)のブランチ名を指定することで、ローカルリポジトリにそのブランチ名が追跡ブランチ(例ではmasterブランチのこと)として作成されリモートリポジトリの同期に利用されるブランチとして使用できます。
1 2 3 4 5 6 7 8 9 10 11 |
~/LocalRepos/TestProject (master) $ ls ~/LocalRepos/TestProject (master) $ git checkout master Branch 'master' set up to track remote branch 'master' from 'origin'. Already on 'master' ~/LocalRepos/TestProject (master) $ ls file1.txt file2.txt ~/LocalRepos/TestProject (master) $ git log --oneline --all --graph --decorate * dfff24b (origin/b1) b1 3 commit | * 3e75d1d (HEAD -> master, origin/master) 2 commit |/ * 220b89b 1 commit |
どのブランチを追跡しているかは
1 |
git branch -vv |
で確認できます。
プッシュ。リモートリポジトリへの記録 (git push)
プッシュはローカルリポジトリの情報をリモートリポジトリへと記録することができます。
ローカルリポジトリの情報をリモートリポジトリへ記録する際はリポジトリ間の整合性が重要になります。
リモートリポジトリにローカルリポジトリとは違う更新内容があったりするとプッシュは失敗します。その場合はフェッチを行い、リモートリポジトリの内容をマージやリベースで取り込んだ後に再度プッシュを行います。
以下は競合がなくプッシュを行われた例になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
~/LocalRepos/TestProject (master) $ touch file4.txt ~/LocalRepos/TestProject (master) $ git add file4.txt ~/LocalRepos/TestProject (master) $ git commit -m '4 commit' [master db6018d] 4 commit 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 file4.txt ~/LocalRepos/TestProject (master) $ git log --oneline --all --graph --decorate * db6018d (HEAD -> master) 4 commit * 3e75d1d (origin/master) 2 commit | * dfff24b (origin/b1, b1) b1 3 commit |/ * 220b89b 1 commit ~/LocalRepos/TestProject (master) $ ~/LocalRepos/TestProject (master) $ git push Enumerating objects: 3, done. Counting objects: 100% (3/3), done. Delta compression using up to 2 threads Compressing objects: 100% (2/2), done. Writing objects: 100% (2/2), 233 bytes | 233.00 KiB/s, done. Total 2 (delta 0), reused 0 (delta 0), pack-reused 0 To /home/ubuntu/RemoteRepos/TestProject.git 3e75d1d..db6018d master -> master |
プッシュが成功するとリモート追跡ブランチ(origin/masterのこと)の位置が動いていることが分かります。
1 2 3 4 5 6 |
~/LocalRepos/TestProject (master) $ git log --oneline --all --graph --decorate * db6018d (HEAD -> master, origin/master) 4 commit * 3e75d1d 2 commit | * dfff24b (origin/b1, b1) b1 3 commit |/ * 220b89b 1 commit |
プル。フェッチとマージの連続操作 (git pull)
git pullはフェッチとマージの連続操作として利用できます。Gitの設定によってはフェッチとリベースとしても利用でき、プロジェクト環境によって様々な設定があります。
私の環境のデフォルト設定ではfast forward(ff)ができない場合はフェッチだけを行うようです。
fast forwardとは片方のブランチのコミット履歴が進んでいる場合、そのままそのコミット履歴を取り込むことです。
補足として、git mergeでfast forwardを行わないオプションとして--no-ffオプションやGitの設定の値としてno-ffがあります。
Gitの基本的なデフォルト値はffの利用ですが、プロジェクトのバージョン管理の方法としてno-ffを利用する場合もあります。
以下はローカルリポジトリに新しいコミットがなく、git pullを行った例です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
~/LocalRepos/TestProject (master) $ git log --oneline --all --graph --decorate * db6018d (HEAD -> master, origin/master) 4 commit * 3e75d1d 2 commit | * dfff24b (origin/b1, b1) b1 3 commit |/ * 220b89b 1 commit ~/LocalRepos/TestProject (master) $ ~/LocalRepos/TestProject (master) $ git pull --出力省略(後述)-- ~/LocalRepos/TestProject (master) $ git log --oneline --all --graph --decorate * 3782b30 (HEAD -> master, origin/master) 5 commit * db6018d 4 commit * 3e75d1d 2 commit | * dfff24b (origin/b1, b1) b1 3 commit |/ * 220b89b 1 commit |
上の例で省略したgit pullの出力は以下のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
~/LocalRepos/TestProject (master) $ git pull remote: Enumerating objects: 3, done. remote: Counting objects: 100% (3/3), done. remote: Compressing objects: 100% (2/2), done. remote: Total 2 (delta 1), reused 0 (delta 0), pack-reused 0 Unpacking objects: 100% (2/2), 195 bytes | 195.00 KiB/s, done. From /home/ubuntu/RemoteRepos/TestProject db6018d..3782b30 master -> origin/master Updating db6018d..3782b30 Fast-forward file5.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 file5.txt |
競合を起こした場合
私の環境では競合を起こした場合はフェッチのみが行われました。以下は手作業でマージ操作を行った例になります。
git mergetoolはGitの設定でマージするときに利用するエディタをしっかり指定していた場合は-tオプションでエディタを指定する必要ありません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
~/LocalRepos/TestProject (master) $ git log --oneline --all --graph --decorate * ceed863 (HEAD -> master) 6-2 commit | * 317fb9e (origin/master) 6 commit |/ * 3782b30 5 commit * db6018d 4 commit * 3e75d1d 2 commit | * dfff24b (origin/b1, b1) b1 3 commit |/ * 220b89b 1 commit ~/LocalRepos/TestProject (master) $ git merge origin/master Auto-merging file6.txt CONFLICT (add/add): Merge conflict in file6.txt Automatic merge failed; fix conflicts and then commit the result. ~/LocalRepos/TestProject (master|MERGING) $ git mergetool -t vimdiff Merging: file6.txt Normal merge conflict for 'file6.txt': {local}: created file {remote}: created file 3 個のファイルが編集を控えています ~/LocalRepos/TestProject (master|MERGING) $ git commit -m '6 mergetool' [master a7b54aa] 6 mergetool ~/LocalRepos/TestProject (master) $ |
コミットまで操作を行なったら、競合していた内容をリモートリポジトリへ記録するためにプッシュを行います。
この時、私は変なコミットメッセージ(例なので基本的に変なコミットメッセージですが(汗))をつけてコミットしていたことに気づいていませんでした。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
~/LocalRepos/TestProject (master) $ git log --oneline --all --graph --decorate * a7b54aa (HEAD -> master) 6 mergetool |\ | * 317fb9e (origin/master) 6 commit * | ceed863 6-2 commit |/ * 3782b30 5 commit * db6018d 4 commit * 3e75d1d 2 commit | * dfff24b (origin/b1, b1) b1 3 commit |/ * 220b89b 1 commit ~/LocalRepos/TestProject (master) $ git push Enumerating objects: 9, done. Counting objects: 100% (9/9), done. Delta compression using up to 2 threads Compressing objects: 100% (4/4), done. Writing objects: 100% (6/6), 508 bytes | 254.00 KiB/s, done. Total 6 (delta 2), reused 0 (delta 0), pack-reused 0 To /home/ubuntu/RemoteRepos/TestProject.git 317fb9e..a7b54aa master -> master ~/LocalRepos/TestProject (master) $ git log --oneline --all --graph --decorate * a7b54aa (HEAD -> master, origin/master) 6 mergetool |\ | * 317fb9e 6 commit * | ceed863 6-2 commit |/ * 3782b30 5 commit * db6018d 4 commit * 3e75d1d 2 commit | * dfff24b (origin/b1, b1) b1 3 commit |/ * 220b89b 1 commit |
プッシュは完了しましたが、変なコミットメッセージをつけたままプッシュしてしまいました。リモートリポジトリが誰かと共同で利用しているリポジトリの場合は修正を諦めるか管理者や関係者等と相談する必要があるでしょう。リモートリポジトリがプライベート利用の場合は勝手に強制プッシュを行って修正するという選択肢があります。
強制プッシュでの修正の例
ここでのリモートリポジトリは完全にプライベート利用のため、強制プッシュの修正を行ってみます。まず、リモートリポジトリの設定でdenyNonFastforwardsをfalseに変更します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
~/RemoteRepos/TestProject.git (BARE:master) $ cat config [core] repositoryformatversion = 0 filemode = true bare = true sharedrepository = 1 [receive] denyNonFastforwards = true ~/RemoteRepos/TestProject.git (BARE:master) $ vi config ~/RemoteRepos/TestProject.git (BARE:master) $ cat config [core] repositoryformatversion = 0 filemode = true bare = true sharedrepository = 1 [receive] #denyNonFastforwards = true denyNonFastforwards = false |
ローカルリポジトリのコミットメッセージを変更して、強制プッシュを行います。強制プッシュのオプションとして--force-with-leaseオプションという-fオプションより共同作業を破壊するリスクを減らすオプションもありますが、ここではプライベートなリモートリポジトリなので簡単に-fオプションを使って強制プッシュを行っています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
~/LocalRepos/TestProject (master) $ git commit --amend [master 072c727] 6 merge commit Date: Thu Apr 4 14:21:47 2024 +0900 ~/LocalRepos/TestProject (master) $ git log --oneline --all --graph --decorate * 072c727 (HEAD -> master) 6 merge commit |\ | | * a7b54aa (origin/master) 6 mergetool | |/| |/|/ | * 317fb9e 6 commit * | ceed863 6-2 commit |/ * 3782b30 5 commit * db6018d 4 commit * 3e75d1d 2 commit | * dfff24b (origin/b1, b1) b1 3 commit |/ * 220b89b 1 commit ~/LocalRepos/TestProject (master) $ git push -f origin master Enumerating objects: 7, done. Counting objects: 100% (7/7), done. Delta compression using up to 2 threads Compressing objects: 100% (2/2), done. Writing objects: 100% (3/3), 290 bytes | 145.00 KiB/s, done. Total 3 (delta 1), reused 0 (delta 0), pack-reused 0 To /home/ubuntu/RemoteRepos/TestProject.git + a7b54aa...072c727 master -> master (forced update) ~/LocalRepos/TestProject (master) $ git log --oneline --all --graph --decorate * 072c727 (HEAD -> master, origin/master) 6 merge commit |\ | * 317fb9e 6 commit * | ceed863 6-2 commit |/ * 3782b30 5 commit * db6018d 4 commit * 3e75d1d 2 commit | * dfff24b (origin/b1, b1) b1 3 commit |/ * 220b89b 1 commit |
これで、リモートリポジトリのコミットメッセージを修正することができました。あとはリモートリポジトリの設定を元に戻しても良いでしょう。
プル。フェッチとリベースの連続操作 (git pull --rebase)
リモートリポジトリの変更内容をリベースでローカルリポジトリへ統合します。ローカルリポジトリと競合を起こしていない場合は通常のpullと同じようにリモートリポジトリの内容を取り込んだ後にローカルリポジトリの内容を再適用します。
以下はローカルリポジトリに新しいコミットがなく、git pull --rebaseを行った例です。
1 2 3 4 5 6 7 8 9 |
~/LocalRepos/TestProj (master) $ git log --oneline --all --graph --decorate * bceb0f6 (HEAD -> master, origin/master) 2 commit * 5cd29f2 1 commit ~/LocalRepos/TestProj (master) $ git pull --rebase --出力省略-- ~/LocalRepos/TestProj (master) $ git log --oneline --all --graph --decorate * ee78eff (HEAD -> master, origin/master) 3 commit * bceb0f6 2 commit * 5cd29f2 1 commit |
競合を起こした場合
競合を起こした場合はリモートリポジトリの内容を取り込まれてから、その後にローカルリポジトリの内容を再適用していって競合内容を解決することになります。
競合を解決した後はローカルリポジトリのコミット内容を、そのまま通常のコミット内容をリモートリポジトリにプッシュするように、リモートリポジトリへとプッシュできるような状態になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
~/LocalRepos/TestProj (master) $ git log --oneline --all --graph --decorate * a7064e5 (HEAD -> master) 4-2 commit * ee78eff (origin/master) 3 commit * bceb0f6 2 commit * 5cd29f2 1 commit ~/LocalRepos/TestProj (master) $ git pull --rebase --出力省略-- Could not apply a7064e5... 4-2 commit ~/LocalRepos/TestProj (master|REBASE 1/1) $ git mergetool -t vimdiff --出力省略-- ~/LocalRepos/TestProj (master|REBASE 1/1) $ git rebase --continue --出力省略(コミットメッセージの編集)-- ~/LocalRepos/TestProj (master) $ git log --oneline --all --graph --decorate * 110eaa8 (HEAD -> master) 4-2 commit * 49ba385 (origin/master) 4 commit * ee78eff 3 commit * bceb0f6 2 commit * 5cd29f2 1 commit ~/LocalRepos/TestProj (master) $ git push --出力省略(pushの成功)-- ~/LocalRepos/TestProj (master) $ git log --oneline --all --graph --decorate * 110eaa8 (HEAD -> master, origin/master) 4-2 commit * 49ba385 4 commit * ee78eff 3 commit * bceb0f6 2 commit * 5cd29f2 1 commit |
ローカルリポジトリのコミット内容が複数ある場合もリモートリポジトリの内容を取り込んだ後に、ローカルリポジトリのコミット内容をその複数個を順番に再適用してリポジトリの内容を統合していきます。
競合を解決してリポジトリをローカルリポジトリで統合した内容はそのままプッシュしてもいいです。ここでは行っていませんが、リモートリポジトリにプッシュする前ならば、必要があれば、さらにコミット内容をgit rebase -iを用いてsquashの機能を利用してローカルリポジトリだけにあるコミット内容を統合した後にリモートリポジトリにプッシュすることも選択肢として取れます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
~/LocalRepos/TestProj (master) $ git log --oneline --all --graph --decorate * 16f5a88 (HEAD -> master) 6-2 commit * b93ad04 5-2 commit * 110eaa8 (origin/master) 4-2 commit * 49ba385 4 commit * ee78eff 3 commit * bceb0f6 2 commit * 5cd29f2 1 commit ~/LocalRepos/TestProj (master) $ git pull --rebase --出力省略-- ~/LocalRepos/TestProj (master|REBASE 1/2) $ git mergetool -t vimdiff --出力省略(vimdiffでの編集)-- ~/LocalRepos/TestProj (master|REBASE 1/2) $ git rebase --continue --出力省略(コミットメッセージの編集)-- ~/LocalRepos/TestProj (master|REBASE 2/2) $ git mergetool -t vimdiff --出力省略(vimdiffでの編集)-- ~/LocalRepos/TestProj (master|REBASE 2/2) $ git rebase --continue --出力省略(コミットメッセージの編集)-- ~/LocalRepos/TestProj (master) $ git log --oneline --all --graph --decorate * c6363f0 (HEAD -> master) 6-2 commit * 7400f59 5-2 commit * e537955 (origin/master) 6 commit * f1b650b 5 commit * 110eaa8 4-2 commit * 49ba385 4 commit * ee78eff 3 commit * bceb0f6 2 commit * 5cd29f2 1 commit |
リベースを用いるとリポジトリのコミット履歴が一直線になり、とてもシンプルなものとなります。また、リモートリポジトリの内容をシステム上であまり変化がないもの(安定したもの)や清書したものとして扱い、ローカルリポジトリのパッチ内容をリモートリポジトリにプッシュするまでは変化をさせやすいもの(不安定なもの)やまだ下書き段階みたいなものとして扱うとすると、マージよりもリベースで統合していく方がより自然な感じに見えるかもしれません。また、コミット履歴はインクリメンタルな開発がよりできていると感じられるかもしれません。
リモートリポジトリの名前を表示 (git remote show)
git remote showはリモートリポジトリの名前を表示できます。
1 2 3 |
~/LocalRepos/TestProject (master) $ git remote show Bob origin |
また、git remote -vはリモートリポジトリのより詳しい情報を確認できます。
1 2 3 4 5 |
~/LocalRepos/TestProject (master) $ git remote -v Bob /home/ubuntu/RemoteRepos/TestProject_Bob.git (fetch) Bob /home/ubuntu/RemoteRepos/TestProject_Bob.git (push) origin /home/ubuntu/RemoteRepos/TestProject.git (fetch) origin /home/ubuntu/RemoteRepos/TestProject.git (push) |
リモートリポジトリの登録の名前の変更 (git remote rename)
git remote renameでリモートリポジトリで登録した名前を変更できます。
1 2 3 4 5 6 7 8 9 10 11 12 |
~/LocalRepos/TestProject (master) $ git remote -v Bob /home/ubuntu/RemoteRepos/TestProject_Bob.git (fetch) Bob /home/ubuntu/RemoteRepos/TestProject_Bob.git (push) origin /home/ubuntu/RemoteRepos/TestProject.git (fetch) origin /home/ubuntu/RemoteRepos/TestProject.git (push) ~/LocalRepos/TestProject (master) $ ~/LocalRepos/TestProject (master) $ git remote rename Bob Alice ~/LocalRepos/TestProject (master) $ git remote -v Alice /home/ubuntu/RemoteRepos/TestProject_Bob.git (fetch) Alice /home/ubuntu/RemoteRepos/TestProject_Bob.git (push) origin /home/ubuntu/RemoteRepos/TestProject.git (fetch) origin /home/ubuntu/RemoteRepos/TestProject.git (push) |