git pushコマンドの使い方!解説と競合したときの解決法など

git Git

git pushコマンドの使い方について書いています。

最初にgit pushコマンドについての説明を書いています。
次にgit pushコマンドの使い方と、実際にgit pushコマンドを使ったときの動作について解説しています。

git pushコマンドとは?

git pushコマンドを使うことで、Gitのリモートリポジトリに現在のコミット履歴を反映させることが可能です。
例えば、まず下記のようにリモートリポジトリから、git cloneコマンドでリポジトリをクローンします。

git cloneコマンドでリポジトリをクローン

現在はリポジトリのコミットとして、A〜Cの履歴ができている状態です。

その後に、ローカルでファイルを編集してコミットします。
そうすると、コミットDができます。
git commitコマンドでコミット履歴を追加

これをgit pushコマンドを使うことで、リモートリポジトリに反映することが可能です。

git pushコマンドでコミット履歴をリモートリポジトリに更新

既にリモートリポジトリの内容が変わっていて、同じファイルを更新していると競合が発生します。
競合が発生した場合には、マージする必要があります。

git pushコマンドの使い方

git pushコマンドを使ってみます。
ファイルをコミットした状態で、下記のコマンドを実行します。

$ git push origin main

実行すると、下記のようにプッシュされたことが確認できました。

$ git push origin main
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 6 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 288 bytes | 288.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
To https://github.com/yasuaki0206/test-repository.git
   4eb1970..f388882  main -> main

指定しているoriginとmainの2つのパラメータですが
originリポジトリのmainブランチにプッシュするという意味になります。
originは現在使っているリモートリポジトリになります。
mainはブランチなので、他のブランチにプッシュする場合には、ここのパラメータも変わります。

リモートリポジトリを確認するには、git remoteコマンドを使います。
下記のように使っているリポジトリのURLを確認できます。

git remote -v
origin  https://github.com/yasuaki0206/test-repository.git (fetch)
origin  https://github.com/yasuaki0206/test-repository.git (push)

Githubの対象リポジトリを指していることが確認できました。
origin以外にもリモートリポジトリは追加することができ、それぞれにプッシュして更新することが可能です。

ブランチを確認するには、git branchコマンドを使います。
下記のように、コマンドを実行すると、ブランチの一覧が表示されます。

% git branch
* main
  newBranch
  testBranch
git branchコマンドの詳細については、こちらに記載しています。
【Git入門】git branchの使い方!ブランチの作成などトピックス4つ!

git pushした時に競合するパターン

次にgit pushした時に競合が発生するパターンです。

ユーザーAで先にファイルをコミットとプッシュします。
その後にユーザーBが同じファイルをコミットしてプッシュした場合の競合についてです。

ユーザーAで先にファイルをプッシュする

まず、ユーザーAでmain.jsをコミットして、プッシュしました。
main.jsファイルを編集して、処理を1行追加しました。

console.log("test")
console.log("test2")

その後にmain.jsファイルをコミットします。

$ git commit -m "add test2 log"
[main f9675ed] add test2 log
 1 file changed, 1 insertion(+)

コミットした後にプッシュすると、下記のように問題なくプッシュできました。
これで、リモートリポジトリに反映されます。

$ git push origin main
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 6 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 285 bytes | 285.00 KiB/s, done.
Total 3 (delta 1), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
To github.com:yasuaki0206/test-repository.git
   6234004..f9675ed  main -> main

ユーザーBが後からファイルをプッシュする

その後、ユーザーBで同じmain.jsをコミットして、プッシュします。
git pullコマンドなどで、最新状態にしていないソースコードです。

main.jsファイルを編集して、同じ位置の処理を1行追加しました。

console.log("test")
console.log("test3")

その後に、コミットをしてプッシュします。

$ git commit -m "add test3 log"
[main fe3416c] add test3 log
 1 file changed, 1 insertion(+)

コミットした後にプッシュすると、下記のようにエラーが表示されました。

$ git push origin main
To https://github.com/yasuaki0206/test-repository.git
 ! [rejected]        main -> main (non-fast-forward)
error: failed to push some refs to 'https://github.com/yasuaki0206/test-repository.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.

リモートリポジトリの方が進んでいるため、このようにエラーになりました。
この場合はヒントにあるように、git pullコマンドで、最新のコミットを取り込んでから競合を解決してからプッシュします。

実際にgit pullコマンドでファイルを取得します。
そうすると、下記のように競合(コンフリクト)が発生しました!

$ git pull origin main
From https://github.com/yasuaki0206/test-repository
 * branch            main       -> FETCH_HEAD
hint: Pulling without specifying how to reconcile divergent branches is
hint: discouraged. You can squelch this message by running one of the following
hint: commands sometime before your next pull:
hint: 
hint:   git config pull.rebase false  # merge (the default strategy)
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.
Auto-merging main.js
CONFLICT (content): Merge conflict in main.js
Automatic merge failed; fix conflicts and then commit the result.

同じmain.jsファイルを修正したので、競合が発生しています。
ファイルを見ると、このようになっています。

console.log("test")
<<<<<<< HEAD
console.log("test3")
=======
console.log("test2")
>>>>>>> f9675eda83f895d1000fdb3b33f9a6b3b92ad14b

今回はどちらの変更も残すように、下記のように修正しました。

console.log("test")
console.log("test3")
console.log("test2")

このままコミットして、プッシュすれば競合が解決します。
他の人が修正したファイルで、どう修正すれば良いかわからない場合などには、コミットした人に相談して解決すると良いかと思います。

実際にプッシュすると、このようにプッシュが完了しました。

$ git push origin main
Enumerating objects: 10, done.
Counting objects: 100% (10/10), done.
Delta compression using up to 6 threads
Compressing objects: 100% (5/5), done.
Writing objects: 100% (6/6), 608 bytes | 608.00 KiB/s, done.
Total 6 (delta 2), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (2/2), completed with 1 local object.
To https://github.com/yasuaki0206/test-repository.git
   f9675ed..794e26f  main -> main

ファイルが被っていない場合には?

git pushした時に、対象のファイルが被っていない場合です。

ユーザーAが更新したファイルと、ユーザーBが更新したファイルが被っていないという状況を想定します。
違うファイルを更新して、ファイルが被っていない場合でも、ユーザーBがプッシュしようとした時にリモートが更新されていたらpullするようにエラー表示されます。

git pullした後にマージが自動で走るので、そのままマージしてプッシュすると良いです。
ユーザーAがmain.jsを最新にして、既にプッシュしている状態です。

ユーザーBでファイルを別の更新してプッシュする

ユーザーBがtesthoge.jsを更新してプッシュしようとすると、下記のようにエラーになります。

$ git push origin main
To https://github.com/yasuaki0206/test-repository.git
 ! [rejected]        main -> main (non-fast-forward)
error: failed to push some refs to 'https://github.com/yasuaki0206/test-repository.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.

git pullコマンドで、最新のコミットを取得します。

$ git pull origin main

自動マージされて、コミットコメントを入れるようにVim(設定エディタ)が立ち上がります。
今回は、そのまま保存します。

1 Merge branch 'main' of https://github.com/yasuaki0206/test-repository                                    
2 # Please enter a commit message to explain why this merge is necessary,
3 # especially if it merges an updated upstream into a topic branch.
4 #
5 # Lines starting with '#' will be ignored, and an empty message aborts
6 # the commit.

そうすると、ファイルが被ってないので、自動マージされてコミットされた状態になります。
このままプッシュすればOKです。

$ git push origin main
Enumerating objects: 9, done.
Counting objects: 100% (8/8), done.
Delta compression using up to 6 threads
Compressing objects: 100% (5/5), done.
Writing objects: 100% (5/5), 573 bytes | 573.00 KiB/s, done.
Total 5 (delta 2), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
To https://github.com/yasuaki0206/test-repository.git
   9a5bd36..4eb1970  main -> main

プッシュが完了しました。

おわりに

今回はgit pushコマンドについて確認していきました。
リモートリポジトリが更新されている場合は、エラーメッセージが表示されました。

実際にプロジェクトで使う場合には、それぞれのユーザーが作業ブランチを作成して、修正していくようにすればgit push時点で競合することはないです。
そのため、作業ブランチを作成して、機能追加やバグ修正などを行なっていくことをオススメします。

修正が完了した後にプルリクを作成して、競合している場合にはgit mergeコマンドなどで、競合した箇所は解決するようにします。

git mergeコマンドについては、こちらに記載しました。
【Git入門】git mergeの使い方!コマンドでブランチをマージする

コメント

タイトルとURLをコピーしました