How do git references work?
Contents
11. How do git references work?#
Important
This picks up directly from the class 2 sessions ago
We will go back to the test repo and review waht we have there.
cd ../test/
ls
test.txt
cat test.txt
version 1
version 2
git status
On branch main
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: test.txt
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: test.txt
We have a few files and we have content staged and unstaged as changes to those files.
git log
fatal: your current branch 'main' does not have any commits yet
Notice, we have no commits yet even though we had written a commit. This is because the main branch does not point to any commit.
fin .git/objects/ -type f
-bash: fin: command not found
To get a better look, we can list the objects.
find .git/objects/ -type f
.git/objects//0c/1e7391ca4e59584f8b773ecdbbb9467eba1547
.git/objects//d6/70460b4b4aece5915caf5c68d12f560a9fe3e4
.git/objects//d8/329fc1cc938780ffdd9f94e0d364e0ea74f579
.git/objects//e0/9139a38f4fd6d82715c32aab9adfed67a87ba5
.git/objects//83/baae61804e65cc73a7201a7252750c76066a30
We can see that indeed we have one object that is a commit
git cat-file -t e0913
commit
And we can look at its contents
git cat-file -p e0913
tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579
author Sarah M Brown <brownsarahm@uri.edu> 1665005715 -0400
committer Sarah M Brown <brownsarahm@uri.edu> 1665005715 -0400
first commit
Let’s add one more new file to review
echo "new file" > new.txt
first we hash the object. The -w
option writes to the directory.
git hash-object -w new.txt
then we get the hash back
fa49b077972391ad58037050f2a75f74e3671e92
Then we stage it.
git update-index --add --cacheinfo 100644 \
> fa49b077972391ad58037050f2a75f74e3671e92 new.txt
and again we can look on the overall repo
git status
On branch main
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: new.txt
new file: test.txt
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: test.txt
and list out the .git
objects
find .git/objects/ -type f
.git/objects//0c/1e7391ca4e59584f8b773ecdbbb9467eba1547
.git/objects//d6/70460b4b4aece5915caf5c68d12f560a9fe3e4
.git/objects//d8/329fc1cc938780ffdd9f94e0d364e0ea74f579
.git/objects//fa/49b077972391ad58037050f2a75f74e3671e92
.git/objects//e0/9139a38f4fd6d82715c32aab9adfed67a87ba5
.git/objects//83/baae61804e65cc73a7201a7252750c76066a30
git cat-file -p 0c1e
version 1
version 2
then we can stage the second version of our first file
git update-index --add --cacheinfo 100644 \
> 0c1e7391ca4e59584f8b773ecdbbb9467eba1547 test.txt
git status
On branch main
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: new.txt
new file: test.txt
and now we see that everything is staged.
Then we confirm what hash is our previous commit
git cat-file -t e0913
commit
git cat-file -p e0913
tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579
author Sarah M Brown <brownsarahm@uri.edu> 1665005715 -0400
committer Sarah M Brown <brownsarahm@uri.edu> 1665005715 -0400
first commit
Next we write a tree object from the staging area
git write-tree
163b45f0a0925b0655da232ea8a4188ccec615f5
git cat-file -p 163b4
100644 blob fa49b077972391ad58037050f2a75f74e3671e92 new.txt
100644 blob 0c1e7391ca4e59584f8b773ecdbbb9467eba1547 test.txt
This tree has the current version of each file.
Now we can make a new commit. We will echo the message into the commit-tree plumbing function with a pipr and then we will tell this commit to point to the tree we just created and that its parent is the first commit.
echo "second commit" | git commit-tree 163b4 -p e0913
cf857a865c6088ab9bf90e2732df967f8e2582ab
But still when we check status
git status
On branch main
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: new.txt
new file: test.txt
The files look staged. This is beacuse of what git status
does. It compares the current working directory (what we see when we do ls) to the staging area and the content that the current branch points to.
find .git/objects -type f
.git/objects/0c/1e7391ca4e59584f8b773ecdbbb9467eba1547
.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4
.git/objects/d8/329fc1cc938780ffdd9f94e0d364e0ea74f579
.git/objects/cf/857a865c6088ab9bf90e2732df967f8e2582ab
.git/objects/16/3b45f0a0925b0655da232ea8a4188ccec615f5
.git/objects/fa/49b077972391ad58037050f2a75f74e3671e92
.git/objects/e0/9139a38f4fd6d82715c32aab9adfed67a87ba5
.git/objects/83/baae61804e65cc73a7201a7252750c76066a30
11.1. Git References#
Recall the .git
directory has many other files in it.
ls .git
HEAD description index objects
config hooks info refs
Let’s look at the refs dir.
ls .git/refs/
heads tags
ls .git/refs/heads
there’s nothing in the heads dir
Though when we use git status
git status
On branch main
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: new.txt
new file: test.txt
we see it is “on main” this is because we set the branch to main , but since we have not written there, we have to do it directly. Notice that when we use the porcelain command for commit, it does this automatically; the porcelain commands do many things.
We can write tothat file directly
echo cf857a865c6088ab9bf90e2732df967f8e2582ab > .git/refs/heads/main
And now if we check git status
git status
On branch main
nothing to commit, working tree clean
we see what we expec.
Alternatively, we can use only a short reference to the hash if we use git update-ref
git update-ref refs/heads/main cf857
Now git log also works.
git log
commit cf857a865c6088ab9bf90e2732df967f8e2582ab (HEAD -> main)
Author: Sarah M Brown <brownsarahm@uri.edu>
Date: Mon Oct 17 16:55:10 2022 -0400
second commit
commit e09139a38f4fd6d82715c32aab9adfed67a87ba5
Author: Sarah M Brown <brownsarahm@uri.edu>
Date: Wed Oct 5 17:35:15 2022 -0400
first commit
Lets create a branch at the point of our first commit.
git update-ref refs/heads/test e0913
git log
commit cf857a865c6088ab9bf90e2732df967f8e2582ab (HEAD -> main)
Author: Sarah M Brown <brownsarahm@uri.edu>
Date: Mon Oct 17 16:55:10 2022 -0400
second commit
commit e09139a38f4fd6d82715c32aab9adfed67a87ba5 (test)
Author: Sarah M Brown <brownsarahm@uri.edu>
Date: Wed Oct 5 17:35:15 2022 -0400
first commit
Notice that the commit history in git log
also lists the branches.
We can also look at the HEAD pointer
git symbolic-ref HEAD
refs/heads/main
update the HEAD directly
git symbolic-ref HEAD refs/heads/test
and see what this does.
git status
On branch test
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: new.txt
modified: test.txt
This is only part of what git checkout
does, because it switches the branch, but does not update the working directory.
11.3. Adding a remote#
We created this repo locally, and we have not set a remote.
git remote
we can add one with
git remote add origin <url/to/remote>
in my case, I’ll use https://github.com/introcompsys/toy-repo-brownsarahm.git
you should use your own.
git remote
origin
ls .git
HEAD description index logs refs
config hooks info objects
ls .git/config
.git/config
cat .git/config
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
precomposeunicode = true
[remote "origin"]
url = https://github.com/introcompsys/toy-repo-brownsarahm.git
fetch = +refs/heads/*:refs/remotes/origin/*
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
adding a remote directly doesn’t link the local branch to the remote branch, so we do that next.
git push -u origin main
Enumerating objects: 7, done.
Counting objects: 100% (7/7), done.
Delta compression using up to 8 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (7/7), 497 bytes | 497.00 KiB/s, done.
Total 7 (delta 0), reused 0 (delta 0), pack-reused 0
To https://github.com/introcompsys/toy-repo-brownsarahm.git
* [new branch] main -> main
branch 'main' set up to track 'origin/main'.
find .git/objects/ -type f
.git/objects//0c/1e7391ca4e59584f8b773ecdbbb9467eba1547
.git/objects//d6/70460b4b4aece5915caf5c68d12f560a9fe3e4
.git/objects//d8/329fc1cc938780ffdd9f94e0d364e0ea74f579
.git/objects//cf/857a865c6088ab9bf90e2732df967f8e2582ab
.git/objects//16/3b45f0a0925b0655da232ea8a4188ccec615f5
.git/objects//fa/49b077972391ad58037050f2a75f74e3671e92
.git/objects//e0/9139a38f4fd6d82715c32aab9adfed67a87ba5
.git/objects//83/baae61804e65cc73a7201a7252750c76066a30
11.4. Review today’s class#
Read the notes and repeat the activity if needed
use
git cat-file
over the objects to draw a graph diagram of your current status in your test directory include your drawing intest_repo_map.md
using mermaid syntax to diagram it. Name each node in your graph with 5-7 characters of the hash and the type. eg0c913 commit
11.5. Prepare for Next Class#
Bring ideas of what you want to write a bash script for and/or a small command line program
Windows only, but important get python working in GitBash
Make sure the gh command line tool works in a bash terminal (either MacOs, Linux, GitBash, or WSL)
11.6. More Practice#
Add “version 3” to the test.txt file and hash that object
Add that to the staging area
Add the tree from the first commit to the staging area as a subdirectory with
git read-tree --prefix=back <hash>
Write the new tree
Make a commit with message “Commit 3” point to that tree and have your second commit as its parent.
Update your diagram in
test_repo_map.md
after the following.Update your
gitplumbingdetail.md