はじめに
これまで、VSCodeの「同期」ボタンを、何気なく使っていました。
どのようなGitコマンドが実行されているか理解できていなかったため、調べた結果を記録します。
VSCodeで「同期」を実行すると何が起きているのか?
Gitログの確認方法
VSCodeのターミナルから「出力」タブを開き、「Git」でフィルターをかけます。

「同期」ボタンを押しただけでも、大量のログが Info レベルで出力されることが分かります。
ここでは、関連する Pull / Push のログのみを抜粋します。
Gitログ
2025-04-15 18:52:47.796 [info] > git pull --tags origin master [5312ms]
2025-03-28 18:52:47.796 [info] From https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/test-repo
* branch master -> FETCH_HEAD
~中略~
2025-03-28 18:52:54.083 [info] > git push origin master:master [6276ms]
2025-03-28 18:52:54.084 [info] remote: Validating objects: 0%
remote: Validating objects: 100%
To https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/test-repo
2e8677d..8a08c6a master -> master
実行されているGitコマンドの内容
git pull --tags origin master
リモート origin/master の更新を取得し、ローカルに取り込み(既定挙動はmerge)
git push origin master:master
ローカルのmasterをリモートに反映
解説
VSCode の「同期」ボタンは、内部的に git pull → git push を順に実行していることが分かりました。
この機能は、リモートの変更を先に取り込み、自分の変更を反映したい場面では便利です。
先にリモートの変更を取り込むため、安全でだとも考えられるでしょう。
しかし、リモートとローカルが分岐していると pull が merge を行い、マージコミットが1つ生成され、履歴が見づらくなります。
たとえば、リモートとローカルの作業が分岐していた場合、以下のようにマージコミットが作成されます。
・リポジトリの状態:
A──B (origin/main)
└─C─D (ローカル)
・git pull(= fetch + merge)の結果:
A──B────────M
└─C─D───┘
↑ マージコミット(M)
マージコミットとは
2つ以上の親コミットを持つ特別なコミット
分岐した2本の履歴を一つにまとめた接合点となる
意図しないマージコミットを作らないために
マージコミットは必要か?
二つのブランチを統合する場合など、マージコミットが適切な場合はあります。
しかし、VSCodeの「同期」ボタンの既定挙動を理解しないばかりに、意図しないマージコミットを作成するのは避けたいですね。
以下に、解決方法を記載します。
VSCodeのGUI操作:「プル - リベース」→「プッシュ」ボタン
VSCode の 「プル(リベース)」 ボタンで変更を取り込み、次に「プッシュ」します。
Gitコマンド:git pull --rebase
リベースは、自分のコミットを最新の先端に付け替える操作です。
上記の分岐例でリベースをすると、ローカルの C, D は付け替えられて C', D' になり、履歴は一直線になります。
A──B──C'──D'
リベースの注意点(重要!)
リベースは名前の通り、コミットIDを付け替えます。
そのため、すでに他人が参照している(Push済みの)履歴を付け替えるのは、原則NGです。
他のユーザが取得しているコミットIDとズレが生じ、可能性があります。
OKなケースは、ローカルにしかない(未pushの)自分のコミットを更新したい場合のみです。
たとえば、以下はOKな例です。
リモート: A──B
ローカル: A──B──c──d (未push)
そこで、リベースをしても、コミットIDが変わるのはローカルのみです。
rebase後: A──B──c'──d' (ローカルのみID変わる)
一方で、以下はNGな例です。
自分がC─D を push 済みのあと、rebase して C'─D' にした場合:
origin/feature: A──B──C──D
ローカル: A──B──C──D (ここでrebase)
rebase後ローカル: A──B──C'──D' ← 旧C,Dとは別物
リベース後、プッシュするには --force が必要となります。
もし、--force で上書きした場合、他の人のローカルには 古い C,D が残ります。
その場合、pullでは直らず、git fetch ののちrebaseし直す or reset し直すなどの対応を強いられます。
VSCodeの設定を変更し、「同期」ボタンを利用
同期ボタンの設定を変えることでも、対応が可能です。
VSCodeの設定で「同期=rebase」にする
設定 → 検索バーに rebase と入力
Git: Pull Rebase をオン(git.pullRebase: true)
Git: Rebase When Sync をオン(git.rebaseWhenSync: true)
まとめ
「同期」= git pull → git push。既定は merge なので分岐時はマージコミットが生まれる。
意図的に避けるなら:
その場だけ → git pull --rebase
常にに避けたい → VS Code 設定で Pull Rebase / Rebase When Sync をオ