🐣

[Git]作業ツリーが存在するときにリモートリポジトリーのコードを取得してみた

2023/07/17に公開

モチベーション

リモートリポジトリーのコードをベースに新しくプロジェクトを作成するときは git clone <リモートリポジトリのURL> を実行すると簡単にリモートリポジトリーのコードを取得できます。ただ、既にプロジェクト(作業ツリー)がローカルに存在しており、リモートリポジトリーの一部/全てのコードを取得したい場合はこれではうまくいきません。この場合にどうしたかをメモします。

環境

  • OS: Windows 11
  • PowerShell: 5.1
  • Git: 2.29.2
  • VS Code: 1.80.1

想定ユースケース

  • ローカルを正として扱う(差分をリモートリポジトリーから取得する)ユースケースを想定
  • 以下のリモートリポジトリーから一部/全てのコードを取得する

事前準備

プロジェクト作成

リモートリポジトリーと同じReactのプロジェクトの方がわかりやすいと考えReactのプロジェクトを作成。

npx create-react-app working_tree_based -- template typescript

Gitでコードを管理する

cd working_tree_based 
git init

ステージを確認してみる

git status

この時点ではまだステージングされていないので以下のメッセージが表示される。

On branch master

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        .gitignore
        README.md
        package-lock.json
        package.json
        public/
        src/

nothing added to commit but untracked files present (use "git add" to track)

ステージング

git add .
git status

ステージングされコミットの準備が整った。

On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
        new file:   .gitignore
        new file:   README.md
        new file:   package-lock.json
        new file:   package.json
        new file:   public/favicon.ico
        new file:   public/index.html
        new file:   public/logo192.png
        new file:   public/logo512.png
        new file:   public/manifest.json
        new file:   public/robots.txt
        new file:   src/App.css
        new file:   src/App.js
        new file:   src/App.test.js
        new file:   src/index.css
        new file:   src/index.js
        new file:   src/logo.svg
        new file:   src/reportWebVitals.js
        new file:   src/setupTests.js

コミット

一旦コミット。

git commit -m "first commit"

リモートリポジトリーから一部コードを取得

ここまでで一旦準備は整ったので、リモートリポジトリーからコードを取得してみる。

リモートリポジトリーの登録

git remote add origin https://github.com/shoji9x9/git_training

ローカル/リモートの差分確認

試しにローカル/リモート双方に存在するREADME.mdの差分を確認してみる。

git diff master origin/master -- README.md

リモートリポジトリーから一部コードを取得

リモートリポジトリーにだけ存在する(ローカルには存在しない).eslintrc.jsを取得してみる。

git checkout origin/master -- .eslintrc.js

ステージを確認してみる

git status

この時点ではまだ.eslintrc.jsはステージングされていないので以下のメッセージが表示される。

On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   .eslintrc.js

ステージング、コミット

後の作業に備え一旦コミット。

git add .eslintrc.js
git commit -m ".eslintrc.js追加"

リモートリポジトリーから一部コード(ディレクトリ)を取得

リモートリポジトリーにだけ存在する(ローカルには存在しない)src/utils/以下の全ファイルを取得してみる(以降のステージの確認、ステージングはここでは割愛)。

git checkout origin/master -- src/utils/*

リモートリポジトリーから一部コードを取得(上書き)

ローカルに存在するREADME.mdをリモートのREADME.mdで上書きしてみる。

git checkout origin/master -- README.md

上書き前に戻す

README.mdは元々ステージされた状態だったため、上記コマンドにより作業ツリー、ステージともにリモートリポジトリーのREADME.mdで上書きされている。これを元に戻すには以下のコマンドを発行する。

git restore -S -W README.md

試してはいないが git reset --hard -- README.md でも同じことを実現できるはず。

【未実現】リモートリポジトリーから一部コードを取得(マージ)

ローカルのREADME.mdとリモートのREADME.mdをマージする。

リモートリポジトリーから全てのコードを取得

pullの設定

設定をせずに git pull すると警告が出るため以下のコマンドを実行。意味合いは
Git 2.27 での git pull 時の warning について 参照。

git config pull.rebase false

pull

git pull origin master

このコマンドを実行すると以下のエラーが発生する。無関係な歴史を持つブランチをマージしようとしたときに発生するエラーの模様。

From https://github.com/shoji9x9/git_training
 * branch            master     -> FETCH_HEAD
fatal: refusing to merge unrelated histories

これを回避するため --allow-unrelated-histories オプションを付けたコマンドを発行する。

git pull --allow-unrelated-histories origin master

するといくつかのファイルで競合が発生。

From https://github.com/shoji9x9/git_training
 * branch            master     -> FETCH_HEAD
CONFLICT (add/add): Merge conflict in package.json
Auto-merging package.json
CONFLICT (add/add): Merge conflict in package-lock.json
Auto-merging package-lock.json
CONFLICT (add/add): Merge conflict in README.md
Auto-merging README.md
Automatic merge failed; fix conflicts and then commit the result.

競合の解消

VS Codeの機能を利用し1つずつ競合を解消。

  • Accept Current Change: ローカルリポジトリーを正とする
  • Accept Incoming Change: リモートリポジトリーを正とする
  • Accept Both Changes: 双方を残す

特定のファイルをステージから削除

git rm --cached package-lock.json

pull以前に削除すると、pullを実行したタイミングで以下のエラーが発生する(リモートリポジトリーにも該当のファイルが存在する場合)。

From https://github.com/shoji9x9/git_training
 * branch            master     -> FETCH_HEAD
error: The following untracked working tree files would be overwritten by merge:
        package-lock.json
Please move or remove them before you merge.
Aborting

ローカルリポジトリーの内容をリモートリポジトリーに反映

push

git push origin master

これで直前にステージから削除したpackage-lock.jsonはリモートリポジトリーにも表示されなくなる。ただし、過去のコミットを見ればpackage-lock.jsonの内容も確認可能なため、万が一機密性の高いファイルをアップロードしてしまった場合は Gitからファイルを完全に削除する方法(BFG Repo-Creaner) など参考に対応する。

Discussion