Wednesday, October 4, 2023

git fetch


Currently, I am curious to find out what Git will do for us behind the scene if we run the 'git fetch' command. Below are the logs coming from my experiment. 


Reference: Git Book


Preparation


Create a new git repository called 'git-fetch-exp' from the git provider such as GitHub.


Step 1:


Run the following commands to keep tracking the local branch and the remote branch.


$ git clone git@github.com:frank/git-fetch-exp.git
Cloning into 'git-fetch-exp'... warning: You appear to have cloned an empty repository.

$ cd git-fetch-exp

    $ echo 'c1' > demo.txt
$ git add .
$ git commit -m 'c1'
[master (root-commit) 823d641] c1 1 file changed, 1 insertion(+) create mode 100644 demo.txt

$ git push
Enumerating objects: 3, done. Counting objects: 100% (3/3), done. Writing objects: 100% (3/3), 212 bytes | 212.00 KiB/s, done. Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 To github.com:frank/git-fetch-exp.git * [new branch] master -> master
   


Check the git status.


    $ git status
On branch master Your branch is up to date with 'origin/master'. nothing to commit, working tree clean


Check the .git tree structure.


    $ tree .git/
.git/ ├── COMMIT_EDITMSG ├── HEAD ├── branches ├── config ├── description ├── hooks │   ├── applypatch-msg.sample │   ├── commit-msg.sample │   ├── fsmonitor-watchman.sample │   ├── post-update.sample │   ├── pre-applypatch.sample │   ├── pre-commit.sample │   ├── pre-merge-commit.sample │   ├── pre-push.sample │   ├── pre-rebase.sample │   ├── pre-receive.sample │   ├── prepare-commit-msg.sample │   ├── push-to-checkout.sample │   └── update.sample ├── index ├── info │   └── exclude ├── logs │   ├── HEAD │   └── refs │   └── heads
│   │   └── master
│   └── remotes │   └── origin │   └── master
├── objects
│   ├── 82 │   │   └── 3d6415e56eb1b4481a24ae16193af80a2ca9ae (git commit object for c1) │   ├── a6 │   │   └── 97b5a1ad379184d8223b14860be0bd1c2f50b2 (git tree object for c1) │   ├── ae │   │   └── 9304576a6ec3419b231b2b9c8e33a06f97f9fb (git blob object for c1)
│   ├── info │   └── pack └── refs ├── heads
│   └── master ├── remotes │   └── origin │   └── master └── tags 19 directories, 27 files


Check more info.


$ git log --oneline --decorate --graph --all
* 823d641 (HEAD -> master, origin/master) c1


Step 2:


Create a 'c2' commit from the UI of git provider to simulate the collaboration with other people.


Step 3:


Run the following commands to add a new 'c3' commit and try to push it to the remote.


    $ echo 'c3' > demo.txt
$ git add .
$ git commit -m 'c3'
[master 96dfa26] c3 1 file changed, 1 insertion(+), 1 deletion(-)

$ git push
To github.com:frank/git-fetch-exp.git ! [rejected] master -> master (fetch first) error: failed to push some refs to 'github.com:frank/git-fetch-exp.git' hint: Updates were rejected because the remote contains work that you do hint: not have locally. This is usually caused by another repository pushing hint: to the same ref. You may want to first integrate the remote changes hint: (e.g., 'git pull ...') before pushing again. hint: See the 'Note about fast-forwards' in 'git push --help' for details.


Check the git status.


    $ git status
On branch master Your branch is ahead of 'origin/master' by 1 commit. (use "git push" to publish your local commits) nothing to commit, working tree clean


Check the .git tree structure.


    $ tree .git/
.git/ ├── COMMIT_EDITMSG ├── HEAD ├── branches ├── config ├── description ├── hooks │   ├── applypatch-msg.sample │   ├── commit-msg.sample │   ├── fsmonitor-watchman.sample │   ├── post-update.sample │   ├── pre-applypatch.sample │   ├── pre-commit.sample │   ├── pre-merge-commit.sample │   ├── pre-push.sample │   ├── pre-rebase.sample │   ├── pre-receive.sample │   ├── prepare-commit-msg.sample │   ├── push-to-checkout.sample │   └── update.sample ├── index ├── info │   └── exclude ├── logs │   ├── HEAD │   └── refs │   └── heads
│   │   └── master
│   └── remotes │   └── origin │   └── master
├── objects
│   ├── 07 │   │   └── 71aea884dd394a7b12783d049f05b5599f41a4 (git blob object for c3)
│   ├── 82 │   │   └── 3d6415e56eb1b4481a24ae16193af80a2ca9ae (git commit object for c1) │   ├── 96 │   │   └── dfa26af1057acfa5fa23ca4a7a92ccebe00f97 (git commit object for c3)
│   ├── a6 │   │   └── 97b5a1ad379184d8223b14860be0bd1c2f50b2 (git tree object for c1) │   ├── ae │   │   └── 9304576a6ec3419b231b2b9c8e33a06f97f9fb (git blob object for c1)
│   ├── be │   │   └── 57a37c6cb18a82fa8381ce465de76a5de48103 (git tree object for c3)
│   ├── info │   └── pack └── refs ├── heads
│   └── master ├── remotes │   └── origin │   └── master └── tags 22 directories, 30 files


Check more info.


$ git log --oneline --decorate --graph --all
* 96dfa26 (HEAD -> master) c3 * 823d641 (origin/master) c1


Step 4:


Run the 'git fetch' commands to fetch commits from the remote.


    $ git fetch
remote: Enumerating objects: 5, done. remote: Counting objects: 100% (5/5), done. remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 Unpacking objects: 100% (3/3), 608 bytes | 608.00 KiB/s, done. From github.com:frank/git-fetch-exp 823d641..5df7c20 master -> origin/master


Check the git status.


    $ git status
On branch master Your branch and 'origin/master' have diverged, and have 1 and 1 different commits each, respectively. (use "git pull" to merge the remote branch into yours) nothing to commit, working tree clean


Check the .git tree structure.


    $ tree .git/
.git/ ├── COMMIT_EDITMSG
├── FETCH_HEAD <= NEW ├── HEAD ├── branches ├── config ├── description ├── hooks │   ├── applypatch-msg.sample │   ├── commit-msg.sample │   ├── fsmonitor-watchman.sample │   ├── post-update.sample │   ├── pre-applypatch.sample │   ├── pre-commit.sample │   ├── pre-merge-commit.sample │   ├── pre-push.sample │   ├── pre-rebase.sample │   ├── pre-receive.sample │   ├── prepare-commit-msg.sample │   ├── push-to-checkout.sample │   └── update.sample ├── index ├── info │   └── exclude ├── logs │   ├── HEAD │   └── refs │   └── heads
│   │   └── master
│   └── remotes │   └── origin │   └── master
├── objects
│   ├── 07 │   │   └── 71aea884dd394a7b12783d049f05b5599f41a4 (git blob object for c3)
│   ├── 16 │   │   └── f9ec009e5568c435f473ba3a1df732d49ce8c3 (git blob object for c2) │   ├── 5d │   │   └── f7c2013b631ba005404a1153983cc810b6d78c (git commit object for c2) │   ├── 6a │   │   └── 13fb3d43e0792ce46f838af08dd8ffdf9eeb48 (git tree object for c2)
│   ├── 82 │   │   └── 3d6415e56eb1b4481a24ae16193af80a2ca9ae (git commit object for c1) │   ├── 96 │   │   └── dfa26af1057acfa5fa23ca4a7a92ccebe00f97 (git commit object for c3)
│   ├── a6 │   │   └── 97b5a1ad379184d8223b14860be0bd1c2f50b2 (git tree object for c1) │   ├── ae │   │   └── 9304576a6ec3419b231b2b9c8e33a06f97f9fb (git blob object for c1)
│   ├── be │   │   └── 57a37c6cb18a82fa8381ce465de76a5de48103 (git tree object for c3)
│   ├── info │   └── pack └── refs ├── heads
│   └── master ├── remotes │   └── origin │   └── master └── tags 25 directories, 34 files


Check more info.


$ git log --oneline --decorate --graph --all
* 96dfa26 (HEAD -> master) c3 | * 5df7c20 (origin/master) c2 |/ * 823d641 c1


The command 'git fetch' will only fetch commits from remote to our local, but it will not change our local branch. We can make our own decision to either merge it or rebase it.


Step 5: Using the 'rebase' approach


Run the 'git rebase' command first.


    $ git rebase origin/master
Auto-merging demo.txt CONFLICT (content): Merge conflict in demo.txt error: could not apply 96dfa26... c3 hint: Resolve all conflicts manually, mark them as resolved with hint: "git add/rm <conflicted_files>", then run "git rebase --continue". hint: You can instead skip this commit: run "git rebase --skip". hint: To abort and get back to the state before "git rebase", run "git rebase --abort". Could not apply 96dfa26... c3


Check the git status.


    $ git status
interactive rebase in progress; onto 5df7c20 Last command done (1 command done): pick 96dfa26 c3
No commands remaining. You are currently rebasing branch 'master' on '5df7c20'. (fix conflicts and then run "git rebase --continue") (use "git rebase --skip" to skip this patch) (use "git rebase --abort" to check out the original branch) Unmerged paths: (use "git restore --staged <file>..." to unstage) (use "git add <file>..." to mark resolution) both modified: demo.txt
no changes added to commit (use "git add" and/or "git commit -a")


Check the .git tree structure.


    $ tree .git/
.git/ ├── AUTO_MERGE <= NEW
├── COMMIT_EDITMSG
├── FETCH_HEAD ├── HEAD ├── MERGE_MSG <= NEW ├── ORIG_HEAD <= NEW ├── REBASE_HEAD <= NEW
├── branches ├── config ├── description ├── hooks │   ├── applypatch-msg.sample │   ├── commit-msg.sample │   ├── fsmonitor-watchman.sample │   ├── post-update.sample │   ├── pre-applypatch.sample │   ├── pre-commit.sample │   ├── pre-merge-commit.sample │   ├── pre-push.sample │   ├── pre-rebase.sample │   ├── pre-receive.sample │   ├── prepare-commit-msg.sample │   ├── push-to-checkout.sample │   └── update.sample ├── index ├── info │   └── exclude ├── logs │   ├── HEAD │   └── refs │   └── heads
│   │   └── master
│   └── remotes │   └── origin │   └── master
├── objects
│   ├── 07 │   │   └── 71aea884dd394a7b12783d049f05b5599f41a4 (git blob object for c3)
│   ├── 16 │   │   └── f9ec009e5568c435f473ba3a1df732d49ce8c3 (git blob object for c2) 
│   ├── 5b │   │   └── fabaa67f7669a81743ef70095fdcfc9e5e2914 (git blob object for auto-merging)
│   ├── 5d │   │   └── f7c2013b631ba005404a1153983cc810b6d78c (git commit object for c2) │   ├── 6a │   │   └── 13fb3d43e0792ce46f838af08dd8ffdf9eeb48 (git tree object for c2)
│   ├── 82 │   │   └── 3d6415e56eb1b4481a24ae16193af80a2ca9ae (git commit object for c1) │   ├── 96 │   │   └── dfa26af1057acfa5fa23ca4a7a92ccebe00f97 (git commit object for c3)
│   ├── a4 │   │   └── 5b62e14f4eb1ee3a12863bd32cf6ab938cbb2b (git tree object for auto-merging)
│   ├── a6 │   │   └── 97b5a1ad379184d8223b14860be0bd1c2f50b2 (git tree object for c1) │   ├── ae │   │   └── 9304576a6ec3419b231b2b9c8e33a06f97f9fb (git blob object for c1)
│   ├── be │   │   └── 57a37c6cb18a82fa8381ce465de76a5de48103 (git tree object for c3)
│   ├── info │   └── pack ├── rebase-merge │   ├── author-script │   ├── done │   ├── drop_redundant_commits │   ├── end │   ├── git-rebase-todo │   ├── git-rebase-todo.backup │   ├── head-name │   ├── interactive │   ├── message │   ├── msgnum │   ├── no-reschedule-failed-exec │   ├── onto │   ├── orig-head │   ├── patch │   └── stopped-sha
└── refs ├── heads
│   └── master ├── remotes │   └── origin │   └── master └── tags 28 directories, 55 files


Check more info.


$ cat .git/AUTO_MERGE
a45b62e14f4eb1ee3a12863bd32cf6ab938cbb2b

$ git cat-file -p a45b62
100644 blob 5bfabaa67f7669a81743ef70095fdcfc9e5e2914 demo.txt

$ git cat-file -p 5bfab
<<<<<<< HEAD c2 ======= c3 >>>>>>> 96dfa26 (c3)

$ cat .git/MERGE_MSG
c3 # Conflicts: # demo.txt

$ cat .git/ORIG_HEAD
96dfa26af1057acfa5fa23ca4a7a92ccebe00f97

$ cat .git/REBASE_HEAD
96dfa26af1057acfa5fa23ca4a7a92ccebe00f97

$ git log --oneline --decorate --graph --all
* 96dfa26 (HEAD -> master) c3 | * 5df7c20 (origin/master) c2 |/ * 823d641 c1


Step 6: 


Resolve the conflict since c2 and c3 modify the same file. 
After that, run the command 'git rebase --continue' to keep rebasing.


    $ vim demo.txt

    $ git add demo.txt
    $ git rebase --continue
[detached HEAD b977483] c3' 1 file changed, 1 insertion(+), 1 deletion(-) Successfully rebased and updated refs/heads/master.


Check the git status.


    $ git status
On branch master Your branch is ahead of 'origin/master' by 1 commit. (use "git push" to publish your local commits) nothing to commit, working tree clean


Check the .git tree structure.


    $ tree .git/
.git/
├── COMMIT_EDITMSG
├── FETCH_HEAD ├── HEAD ├── ORIG_HEAD ├── REBASE_HEAD
├── branches ├── config ├── description ├── hooks │   ├── applypatch-msg.sample │   ├── commit-msg.sample │   ├── fsmonitor-watchman.sample │   ├── post-update.sample │   ├── pre-applypatch.sample │   ├── pre-commit.sample │   ├── pre-merge-commit.sample │   ├── pre-push.sample │   ├── pre-rebase.sample │   ├── pre-receive.sample │   ├── prepare-commit-msg.sample │   ├── push-to-checkout.sample │   └── update.sample ├── index ├── info │   └── exclude ├── logs │   ├── HEAD │   └── refs │   └── heads
│   │   └── master
│   └── remotes │   └── origin │   └── master
├── objects
│   ├── 07 │   │   └── 71aea884dd394a7b12783d049f05b5599f41a4 (git blob object for c3)
│   ├── 16 │   │   └── f9ec009e5568c435f473ba3a1df732d49ce8c3 (git blob object for c2) 
│   ├── 5b │   │   └── fabaa67f7669a81743ef70095fdcfc9e5e2914 (git blob object for auto-merging)
│   ├── 5d │   │   └── f7c2013b631ba005404a1153983cc810b6d78c (git commit object for c2) │   ├── 6a │   │   └── 13fb3d43e0792ce46f838af08dd8ffdf9eeb48 (git tree object for c2)
│   ├── 82 │   │   └── 3d6415e56eb1b4481a24ae16193af80a2ca9ae (git commit object for c1) │   ├── 96 │   │   └── dfa26af1057acfa5fa23ca4a7a92ccebe00f97 (git commit object for c3)
│   ├── a4 │   │   └── 5b62e14f4eb1ee3a12863bd32cf6ab938cbb2b (git tree object for auto-merging)
│   ├── a6 │   │   └── 97b5a1ad379184d8223b14860be0bd1c2f50b2 (git tree object for c1) │   ├── ae │   │   └── 9304576a6ec3419b231b2b9c8e33a06f97f9fb (git blob object for c1)
│   ├── b9 │   │   └── 774831bbe2500eedc5ba0f5a4dc86a8e3c81e3 (git commit object for c3')
│   ├── be │   │   └── 57a37c6cb18a82fa8381ce465de76a5de48103 (git tree object for c3)
│   ├── info │   └── pack
└── refs ├── heads
│   └── master ├── remotes │   └── origin │   └── master └── tags 28 directories, 39 files


Check more info.


$ git log --oneline --decorate --graph --all
* b977483 (HEAD -> master) c3' * 5df7c20 (origin/master) c2 * 823d641 c1


Step 7: 


Run the 'git push' command to push the local changes to the remote.


$ git push
Enumerating objects: 5, done. Counting objects: 100% (5/5), done. Writing objects: 100% (3/3), 248 bytes | 248.00 KiB/s, done. Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 To github.com:frank/git-fetch-exp.git 5df7c20..b977483 master -> master


Check the git status.


    $ git status
On branch master Your branch is up to date with 'origin/master'. nothing to commit, working tree clean


Check more info.


$ git log --oneline --decorate --graph --all
* b977483 (HEAD -> master, origin/master) c3' * 5df7c20 c2 * 823d641 c1


Tuesday, September 26, 2023

git checkout [commit] [path]


Currently, I am curious to find out what Git will do for us behind the scene if we run the 'git checkout [commit] [path]' command. Below are the logs coming from my experiment. 


Reference: Git Book


Preparation


Create a brand new folder and run the 'git init' command.


Step 1:


Run the following commands to keep changing a file and make three commits


    $ echo 'v1' > file.txt
$ git add .
$ git commit -m 'v1'
[master (root-commit) 1491536] v1 1 file changed, 1 insertion(+) create mode 100644 file.txt

    $ echo 'v2' > file.txt
$ git add .
$ git commit -m 'v2'
    [master 9a8fa1e] v2
     1 file changed, 1 insertion(+), 1 deletion(-)

    $ echo 'v3' > file.txt
$ git add .
$ git commit -m 'v3'
[master d0769a6] v3 1 file changed, 1 insertion(+), 1 deletion(-)



Check the git status.


    $ git status
On branch master nothing to commit, working tree clean


It is all synced (the three trees below keep the v3 version of file.txt).


Check the .git tree structure.


    $ tree .git/
.git/ ├── COMMIT_EDITMSG ├── HEAD ├── branches ├── config ├── description ├── hooks │   ├── applypatch-msg.sample │   ├── commit-msg.sample │   ├── fsmonitor-watchman.sample │   ├── post-update.sample │   ├── pre-applypatch.sample │   ├── pre-commit.sample │   ├── pre-merge-commit.sample │   ├── pre-push.sample │   ├── pre-rebase.sample │   ├── pre-receive.sample │   ├── prepare-commit-msg.sample │   ├── push-to-checkout.sample │   └── update.sample ├── index ├── info │   └── exclude ├── logs │   ├── HEAD │   └── refs │   └── heads
│   └── master ├── objects
│   ├── 14 │   │   └── 91536a26a35b6a0037cfa9ccbac70fecdb77d0 (git commit object for v1) │   ├── 25 │   │   └── 7330bfc3b1cce445c8bf7202d88eca9ffff025 (git tree object for v2) │   ├── 29 │   │   └── ef827e8a45b1039d908884aae4490157bcb2b4 (git blob object for v3) │   ├── 62 │   │   └── 6799f0f85326a8c1fc522db584e86cdfccd51f (git blob object for v1) │   ├── 8c │   │   └── 1384d825dbbe41309b7dc18ee7991a9085c46e (git blob object for v2) │   ├── 9a │   │   └── 8fa1eee2b0d2841ffa1e5515935421c3d419e1 (git commit object for v2) │   ├── a7 │   │   └── 949a02518883287c308f0b47e2a4934b111cc3 (git tree object for v3) │   ├── cc │   │   └── 5fda52eb3ed07cce6357ac11e392cd2dbf6d16 (git tree object for v1) │   ├── d0 │   │   └── 769a6fa5bcf4c05f667eb635dd84c1174be895 (git commit object for v3)
│   ├── info │   └── pack └── refs ├── heads
│   └── master └── tags 21 directories, 31 files


Check more info.


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

$ cat .git/refs/heads/master
d0769a6fa5bcf4c05f667eb635dd84c1174be895

$ git ls-files -s
100644 29ef827e8a45b1039d908884aae4490157bcb2b4 0 file.txt (v3 version)

$ git log --oneline --decorate --graph --all
* d0769a6 (HEAD -> master) v3 * 9a8fa1e v2 * 1491536 v1


Step 2:


Let's run the following commands to edit the file.txt as the v4 version and update the Index.


    $ echo 'v4' > file.txt
$ git add .


Check the git status.


    $ git status
On branch master Changes to be committed: (use "git restore --staged <file>..." to unstage) modified: file.txt


Now, both the Index and the working directory keep the v4 version of file.txt.


Then run the 'git checkout [commit][path]' command.


    $ git checkout HEAD file.txt
    Updated 1 path from a7949a0


Check the git status.


    $ git status
On branch master nothing to commit, working tree clean


The [path] both in the Index and the working directory got reset to v3 based on the [commit] which is HEAD in this case.


After running the 'git checkout[commit] [path]' command, we revert the commands from


    $ echo 'v4' > file.txt
$ git add .

to


None