3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

いいかげんgitのことをちゃんと知りたいあなたへ(Gitリポジトリ編)

Last updated at Posted at 2021-02-07

ここからの続きです

GitHubでリポジトリ作ったときの例のアレ

github-sandbox.png

GitホスティングサービスといえばGitHubですよね。
GitHubにリポジトリを作ると、リポジトリの初期化を行うシェルが例示されますが、
いっつもコピペしてガッってやってるだけで、いまいち理解していません。
これを機に、それをひとつずつ追っていきたいと思います。
mac上でポチポチやってます。


まずはGithub上に新しいリポジトリを作ってみましょう

GitHubさんにお世話になります。
アカウントがなければ作って、Repositories -> new から適当にリポジトリを作りましょう。
今回はsandboxというリポジトリを作りました。privateでもpublicでもどちらでもかまいません。
たったいま作られたリポジトリにアクセスしてみると、例のご指示が。
コメントはじぶんの脳内補完です。

### ファイルを作って
$ echo "# sandbox" >> README.md
### ローカルにGitリポジトリを作って
$ git init
### ファイルをステージングして
$ git add README.md
### ステージングした内容をコミットして
$ git commit -m "first commit"
### mainブランチを作ってそこに移動して
$ git branch -M main
### originというリモート追跡ブランチをURLを紐付けたうえで作成して
$ git remote add origin git@github.com:atchy/sandbox.git
### プッシュする
$ git push -u origin main

いっこずつ見ていきましょう

1. README.mdを作成する

適当なディレクトリを作成&移動してから、言われるがまま、したがいましょう。

$ mkdir ~/sandbox && cd ~/sandbox
$ echo "# sandbox" >> README.md

2. git init する

パラメータを指定せずにgit initすると、空のリポジトリを作成します。

$ git init
Initialized empty Git repository in /Users/atchy/sandbox/.git/

ローカルにGitリポジトリが作成されました!
作成したての構成はこうなっています。

$ ls -Al
total 8
drwxr-xr-x  9 atchy  staff  288  2  7 07:47 .git
-rw-r--r--  1 atchy  staff   10  2  7 07:42 README.md

.gitディレクトリができていますね!
つまり、Gitリポジトリの実体は、.gitディレクトリであるということが言えます。
ただこの時点では、ローカルにGitリポジトリが作られただけで、GitHub上のリポジトリとは(まだ)何の関係もありません。

.gitディレクトリの中をのぞいてみましょう。

$ ls -Al .git 
total 24
-rw-r--r--   1 atchy  staff   23  2  7 07:42 HEAD
-rw-r--r--   1 atchy  staff  137  2  7 07:42 config
-rw-r--r--   1 atchy  staff   73  2  7 07:42 description
drwxr-xr-x  14 atchy  staff  448  2  7 07:42 hooks
drwxr-xr-x   3 atchy  staff   96  2  7 07:42 info
drwxr-xr-x   4 atchy  staff  128  2  7 07:42 objects
drwxr-xr-x   4 atchy  staff  128  2  7 07:42 refs

.git/objectsにはGitオブジェクトが配置されています。
いいかげんgitのことをちゃんと知りたいあなたへ(Gitオブジェクト編)をご参照ください。

.git/configファイルにはリポジトリの情報が記録されています。
のぞいてみましょう。

$ cat .git/config 
[core]
	repositoryformatversion = 0
	filemode = true
	bare = false
	logallrefupdates = true
	ignorecase = true
	precomposeunicode = true

coreというセクションだけ書き込まているようです。

Gitリポジトリの重要な要素にHEADがあります。
Pro Gitによると、HEADとは現在作業中のブランチに対するシンボリック参照とのこと。

HEADはファイルなので、中身ををのぞいてみます。

$ cat .git/HEAD 
ref: refs/heads/master

HEAD、つまり現在作業中のブランチは、refs/heads/masterとのこと。
そ、そですか、じぶんmasterブランチで作業中だったですか・・・
中身をのぞいてみましょう。

$ cat .git/refs/heads/master
cat: .git/refs/heads/master: No such file or directory

あり?そんなファイルないけど・・・

git initのマニュアルを見てみます。

$ man git-init

This command creates an empty Git repository - basically a .git directory with subdirectories
for objects, refs/heads, refs/tags,and template files.
An initial HEAD file that references the HEAD of the master branch is also created.

このコマンドは、空のGitリポジトリを作成します。基本的には、objects, refs/heads, refs/tags、
およびテンプレートファイルのサブディレクトリを持つ.gitディレクトリです。
masterブランチのHEADをさす初期のHEADファイルも生成します。

ふむ。
git initすることで、.git/refs/heads/masterをさすHEADファイルが作られるようです。
.git/refsにはブランチ(を指すコミットオブジェクト)やタグを指す参照(ポインタ)が記述されたファイルが格納されていきます。
ただ、現時点ではGitオブジェクトひとつも作成していないので、当然何も登録されていない、ということです。

$ tree -a .git/refs 
.git/refs
├── heads
└── tags

2 directories, 0 files

たしかに何もありませんね。

2. git addしてみる

最初似作成したREADME.mdをステージングします。

$ git add README.md
$ git status
On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
	new file:   README.md

ステージングされてますね。
.git/refsまわりに何か変化はあったでしょうか?

$ tree -a .git/refs 
.git/refs
├── heads
└── tags

2 directories, 0 files

変化なし、と。
次いきます。

3. git commitしてみる

$ git commit -m "first commit"
[master (root-commit) 1c25cf6] first commit
 1 file changed, 1 insertion(+)
 create mode 100644 README.md

commitできました。
.git/refsまわりを確認してみます。

$ tree -a .git/refs           
.git/refs
├── heads
│   └── master
└── tags

2 directories, 1 file

お!
.git/refs/heads/masterができてます!

つまり、

  1. git commitすることによりコミットオブジェクトが作られた
  2. git initしたときにHEAD、つまり作業中のブランチはmasterブランチを指すようになっていた
  3. 作業中のmasterブランチでコミットしたから、.git/refs/heads/masterが作られた

中身は

$ cat .git/refs/heads/master 
34f185d743f99494056929d23e4101d0ec9ba885

$ git cat-file -p 34f185d743f99494056929d23e4101d0ec9ba885
tree 7ea9d65bc6c0b96b08b44bebce84563812dabac1
author atchy <atchy@example.com> 1612655598 +0900
committer atchy <atchy@example.com> 1612655598 +0900

first commit

たしかにさっきのコミットにより作成されたコミットオブジェクトを指しているようです。

4. git branchしてみる

引き続き、指示にしたがいます。

$ git branch -M main

何も起きてないようにも見えますが・・・

$ tree -a .git/refs 
.git/refs
├── heads
│   └── main
└── tags

2 directories, 1 file

さっきまではmasterという名前だったのがmainになっています。

マニュアルによると、

man git-branch

With a -m or -M option, will be renamed to .
If had a corresponding reflog, it is renamed tomatch ,
and a reflog entry is created to remember the branch renaming.
If exists, -M must be used to force the rename to happen.

どうやら、

  • 今のブランチ(HEADが指すブランチ、すなわちmasterブランチ)のブランチ名を変更して、
  • mainというブランチがすでにあればそれを上書きする

という挙動のようです。
つまり、mastermainという名前に変更された、と。

中身をのぞいてみましょう。

$ cat .git/refs/heads/main 
34f185d743f99494056929d23e4101d0ec9ba885

さっきとは同じですね。
つまり、masterという名前がmainに変わっただけ、ということですね。
今後、GitHubさんとしては、デフォルトブランチ名をmainとするようです

5. git remote addしてみる

ここまではローカルリポジトリをコネコネしてるだけでしたが、
いよいよリモートと何やら何かをするような雰囲気です。
だってgit remoteとか言うてますから!

その前に現状を確認しておきましょう。

git remote show

反応ありません。

.git/configの内容は、

$ cat .git/config         
[core]
	repositoryformatversion = 0
	filemode = true
	bare = false
	logallrefupdates = true
	ignorecase = true
	precomposeunicode = true

git init後と変わりないですね。
では、

$ git remote add origin git@github.com:atchy/sandbox.git

しーん。
いったいなにが起こったのでしょうか・・・

$ git remote show
origin

お!
地味ながら、変化がありましたね。
originというリモートが追加されたぽいです

.git/configファイルを見てみます

$ cat .git/config 
[core]
	repositoryformatversion = 0
	filemode = true
	bare = false
	logallrefupdates = true
	ignorecase = true
	precomposeunicode = true
[remote "origin"]
	url = git@github.com:atchy/sandbox.git
	fetch = +refs/heads/*:refs/remotes/origin/*

remoteセクションが追加されてますね!
git remote addはリモート的な何かを追加するコマンドのようです。
順をおって見ていきましょう。

まずはgit remoteコマンドを見直してみましょう。

$ git remote add origin git@github.com:atchy/sandbox.git

という状況から類推するに、

  • originという名前のリモートが追加された
  • urlプロパティはgit@github.com:atchy/sandbox.git
  • fetchプロパティは+refs/heads/*:refs/remotes/origin/*

urlプロパティはなんとなく分かりますよね。
たぶん、gitというgithub.comサーバのatchy/sandbboxディレクトリを指してるかと思います。
scpコマンドと似てますね。
で、問題はfetchプロパティの方ですが・・・
このあたりを考え出すと、もうひとつ記事が書けそうなので、別の機会にします。
とりあえず、リモートリポジトリが登録された、とだけ考えましょう。

リモートリポジトリが追加された、ということは、もうそこへpushすることができるんでしょうか?

$ git push
fatal: The current branch main has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin main

怒られましたね・・・

現在のブランチにはupstreamブランチがありません。
現在のブランチをプッシュして、upstreamをリモートとして設定するには、
git push --set-upstream origin main
を実行してね

と。
むぅぅ、upstreamとはなんぞ?
このあたりを考え出すと(ry
上流ブランチについてはまた次の機会に・・・

git remote addによって、リモートとしてGitHub上のリポジトリが登録されましたが、
現在のブランチ(masterブランチ)を、リモート上のどのブランチにプッシュするか、
が分からない(設定されていない)ため、現状ではプッシュが失敗します。
まあ、言われてみればそうですよね・・・
その問題を解決するために最後のステップに進みます。

6. git pushしてみる

さあいよいよプッシュします!

$ git push -u origin main
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), 221 bytes | 221.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
To github.com:atchy/sandbox.git
 * [new branch]      main -> main
Branch 'main' set up to track remote branch 'main' from 'origin'.

成功したようですね。
GitHub上も表示に変化がありました(ファイルいっこしかないですがw)

after_push.png

コマンドの意味をみてみましょう。
まずはマニュアルを参照してみます。

$ man git-push

-uオプションは

-u, --set-upstream
For every branch that is up to date or successfully pushed, add upstream (tracking) reference

さっき怒られたときに付いてたオプションと同じですね。
その意味は
upstream (tracking) referenceを追加する、と。
さっきはupstreamブランチが設定されていなかったので、プッシュに失敗しましたが、
今は設定されているのでしょうか?

.git/configをのぞくと、

$ cat .git/config 
[core]
	repositoryformatversion = 0
	filemode = true
	bare = false
	logallrefupdates = true
	ignorecase = true
	precomposeunicode = true
[remote "origin"]
	url = git@github-atchy:atchy/sandbox.git
	fetch = +refs/heads/*:refs/remotes/origin/*
[branch "main"]
	remote = origin
	merge = refs/heads/main

branchセクションが追加されています。

さらに、.git/refsまわりを見てみると、

$ tree -a .git/refs 
.git/refs
├── heads
│   └── main
├── remotes
│   └── origin
│       └── main
└── tags

4 directories, 2 files

.git/refs/remotes/origin/mainができてますね。

まとめると、

  • mainブランチのリモートはoriginとする
  • リモートの参照として.git/refs/origin/mainを配置する

と。

mergeプロパティについては、いまはそっとしておきます・・・

おわりに

知れば知るほどgitの奥深さと、じぶんがぜっんぜんgitのことを
理解していなかったのかが、身に沁みてわかります。
これからも精進していきます。

次回予告

とはいえ、リモートの存在意義とか、上流ブランチとか、リモート追跡ブランチとか、
腑に落ちない点がまだまだありますので、そのあたりを紐解いていきたいでっす

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?