Wednesday, July 12, 2023

git rebase -i

     

Currently, I am curious to find out what Git will do for us behind the scene if we run the 'git rebase -i' commands. 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 simulate the situation above.


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

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

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

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


Check the git status.


    $ git status
On branch 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 ├── objects
│   ├── 07 │   │   └── 71aea884dd394a7b12783d049f05b5599f41a4 (git blob object for c3) │   ├── 0c │   │   └── b5816af1824bf60da8b472b8752bf5a4805be1 (git commit object for c3) │   ├── 16 │   │   └── f9ec009e5568c435f473ba3a1df732d49ce8c3 (git blob object for c2) 
│   ├── 55 │   │   └── 4b493ae2938685a42afe6b6db5b43718cd6288 (git tree object for c4)  │   ├── 82 │   │   └── 098e7689178db6638f193ceb32f5ed807b73ca (git commit object for c4) 
│   ├── 83 │   │   └── 5da11381dee94c71a04164cdaa533d0673e4e5 (git tree object for c1) │   ├── 96 │   │   └── 8a4b6caa8b55a68098e0495fbd9e75a7d05efa (git tree object for c2) │   ├── 9c │   │   └── e38c88738074a43829866d92b9fccd0365e012 (git commit object for c2) 
│   ├── a1 │   │   └── 03f673dd1b7c5727aa0ae0100419adc50e1b76 (git blob object for c4) 
│   ├── ae │   │   └── 9304576a6ec3419b231b2b9c8e33a06f97f9fb (git blob object for c1) │   ├── db │   │   └── 67b8366893a7726d3149b959245ddafe6db70f (git commit object for c1) │   ├── fc │   │   └── 88a9c9de3667ac068fa176bb960ed4b22c5d4a (git tree object for c3)
│   ├── info │   └── pack └── refs ├── heads
│   └── master └── tags 24 directories, 34 files


Check more info.


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

$ cat .git/refs/heads/master
82098e7689178db6638f193ceb32f5ed807b73ca

$ git ls-files -s
100644 ae9304576a6ec3419b231b2b9c8e33a06f97f9fb 0 c1.txt 100644 16f9ec009e5568c435f473ba3a1df732d49ce8c3 0 c2.txt 100644 0771aea884dd394a7b12783d049f05b5599f41a4 0 c3.txt
100644 a103f673dd1b7c5727aa0ae0100419adc50e1b76 0 c4.txt

$ git log --oneline --decorate --graph --all
* 82098e7 (HEAD -> master) c4 * 0cb5816 c3
* 9ce38c8 c2 * db67b83 c1


Step 2:


Run the 'git rebase -i db67b83' command.


    $ git rebase -i db67b83

  //------------------Prompt Message ----------------------
pick 9ce38c8 c2
pick 0cb5816 c3
pick 82098e7 c4
# Rebase db67b83..82098e7 onto db67b83(3 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup [-C | -c] <commit> = like "squash" but keep only the previous
#                    commit's log message, unless -C is used, in which case
#                    keep only this commit's message; -c is same as -C but
#                    opens the editor
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified); use -c <commit> to reword the commit message
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
//----------------------------------------


Let us change the message as the following:

Drop the c2 commit and change the order of the C4 and C3 commits.


  //------------------Prompt Message ----------------------
drop 9ce38c8 c2
pick 82098e7 c4
pick 0cb5816 c3
//----------------------------------------

Successfully rebased and updated refs/heads/master.


Check the git status.


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


Check the .git tree structure.


    $ tree .git/
.git/ ├── AUTO_MERGE
├── COMMIT_EDITMSG ├── HEAD 
├── ORIG_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
│   ├── 07 │   │   └── 71aea884dd394a7b12783d049f05b5599f41a4 (git blob object for c3) │   ├── 0c │   │   └── b5816af1824bf60da8b472b8752bf5a4805be1 (git commit object for c3) │   ├── 16 │   │   └── f9ec009e5568c435f473ba3a1df732d49ce8c3 (git blob object for c2) 
│   ├── 22
│   │   └── ccdb6783ef6f2ebfae9a534995451f648c6e38 (git commit object for new c3) <= NEW
│   ├── 55 │   │   └── 4b493ae2938685a42afe6b6db5b43718cd6288 (git tree object for c4)  │   ├── 59 │   │   └── 4d3351074627c9137889a75978f0df9d1cc6bd (git commit object for new c4) <= NEW
│   ├── 82 │   │   └── 098e7689178db6638f193ceb32f5ed807b73ca (git commit object for c4) 
│   ├── 83 │   │   └── 5da11381dee94c71a04164cdaa533d0673e4e5 (git tree object for c1) │   ├── 96 │   │   └── 8a4b6caa8b55a68098e0495fbd9e75a7d05efa (git tree object for c2) │   ├── 9c │   │   └── e38c88738074a43829866d92b9fccd0365e012 (git commit object for c2) 
│   ├── a1 │   │   └── 03f673dd1b7c5727aa0ae0100419adc50e1b76 (git blob object for c4) 
│   ├── a6 │   │   └── 2c41aa34590add113a96265734f74754ea2ee9 (git tree object for new c3) <= NEW
│   ├── ae │   │   └── 9304576a6ec3419b231b2b9c8e33a06f97f9fb (git blob object for c1) │   ├── db │   │   └── 67b8366893a7726d3149b959245ddafe6db70f (git commit object for c1) 
│   ├── dc │   │   └── 813e91d4835e21e01f4917a510a0c95824a2da (git tree object for new c4) <= NEW
│   ├── fc │   │   └── 88a9c9de3667ac068fa176bb960ed4b22c5d4a (git tree object for c3)
│   ├── info │   └── pack └── refs ├── heads
│   └── master └── tags 28 directories, 40 files


Check more info.


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

$ cat .git/ORIG_HEAD
82098e7689178db6638f193ceb32f5ed807b73ca

$ cat .git/AUTO_MERGE
a62c41aa34590add113a96265734f74754ea2ee9

$ cat .git/refs/heads/master
22ccdb6783ef6f2ebfae9a534995451f648c6e38

$ git ls-files -s
100644 ae9304576a6ec3419b231b2b9c8e33a06f97f9fb 0 c1.txt 100644 0771aea884dd394a7b12783d049f05b5599f41a4 0 c3.txt
100644 a103f673dd1b7c5727aa0ae0100419adc50e1b76 0 c4.txt

$ git log --oneline --decorate --graph --all
* 22ccdb6 (HEAD -> master) c3 * 594d335 c4 * db67b83 c1


After rebasing (interactive mode), we can remove commits, and we can reorder the commits (swap c3 and c4).


Thursday, July 6, 2023

git cherry-pick

    

Currently, I am curious to find out what Git will do for us behind the scene if we run the 'git cherry-pick' commands. 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 simulate the situation above.


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

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

$ git checkout -b dev
Switched to a new branch 'dev'

    $ echo 'c3' > test.txt
$ git add .
$ git commit -m 'c3'
[dev d27e424] c3 1 file changed, 1 insertion(+), 1 deletion(-)

$ git checkout master
Switched to branch 'master'

    $ echo 'c4' > test.txt
$ git add .
$ git commit -m 'c4'
[master 71823ca] c4 1 file changed, 1 insertion(+), 1 deletion(-)

$ git checkout dev
Switched to branch 'dev'

    $ echo 'c5' > test.txt
$ git add .
$ git commit -m 'c5'
[dev ca63078] c5 1 file changed, 1 insertion(+), 1 deletion(-)

$ git checkout master
    Switched to branch 'master'


Check the git status.


    $ git status
On branch 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
│   ├── dev
│   └── master ├── objects
│   ├── 07 │   │   └── 71aea884dd394a7b12783d049f05b5599f41a4 (git blob object for c3) │   ├── 16 │   │   └── f9ec009e5568c435f473ba3a1df732d49ce8c3 (git blob object for c2) │   ├── 3d │   │   └── 3095743da8025788f376069d9c07b9d867d5c1 (git tree object for c4) │   ├── 61 │   │   └── 8ce2788f58e3fb609e5666ab6c433f37423604 (git tree object for c5) │   ├── 71 │   │   └── 823caf53fc21b9909e073361dac6f9e3cfba96 (git commit object for c4) │   ├── a1 │   │   └── 03f673dd1b7c5727aa0ae0100419adc50e1b76 (git blob object for c4) │   ├── ae │   │   ├── 8f0444ccad90b277e3c51220c8d1f1af0cfba0 (git commit object for c1) │   │   └── 9304576a6ec3419b231b2b9c8e33a06f97f9fb (git blob object for c1) │   ├── b5 │   │   └── fab02de1c1f88003afeb7e98cf84a141bff039 (git tree object for c3) │   ├── b7 │   │   └── 19c3c104eefb9edef6b06d190e140f8af62377 (git commit object for c2) │   ├── c0 │   │   └── b072a3d368667939677b9315360631a100ecde (git tree object for c2) │   ├── c3 │   │   └── 6357109ce20af8f90df3c0dd0784e89408d707 (git blob object for c5) │   ├── ca │   │   └── 63078ddb21c6db42795ed3a20a867dee2d9ed8 (git commit object for c5) │   ├── d2 │   │   └── 7e4240f4faf17a95884f009416bfafd88a4572 (git commit object for c3) │   ├── f1 │   │   └── 8c7b882bf09e79d96b692c31450cf59344fbf4 (git tree object for c1)
│   ├── info │   └── pack └── refs ├── heads
│   ├── dev
│   └── master └── tags 26 directories, 39 files


Check more info.


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

$ cat .git/refs/heads/master
71823caf53fc21b9909e073361dac6f9e3cfba96

$ cat .git/refs/heads/dev
ca63078ddb21c6db42795ed3a20a867dee2d9ed8

$ git ls-files -s
100644 a103f673dd1b7c5727aa0ae0100419adc50e1b76 0 test.txt

$ git log --oneline --decorate --graph --all
* ca63078 (dev) c5 * d27e424 c3 | * 71823ca (HEAD -> master) c4 |/ * b719c3c c2 * ae8f044 c1


Step 2:


Imagine that in the mater branch, we only want the c3 commit from the dev branch commit history.

Run the 'git cherry-pick' command.


    $ git cherry-pick d27e424
Auto-merging test.txt CONFLICT (content): Merge conflict in test.txt error: could not apply d27e424... c3 hint: After resolving the conflicts, mark them with hint: "git add/rm <pathspec>", then run hint: "git cherry-pick --continue". hint: You can instead skip this commit with "git cherry-pick --skip". hint: To abort and get back to the state before "git cherry-pick", hint: run "git cherry-pick --abort".


Resolve the conflict and run 'git cherry-pick --continue'.


$ git cherry-pick --continue
[master 1a42c7d] c3 Date: Thu Jul 6 00:01:02 2023 -0700 1 file changed, 1 insertion(+)


Check the git status.


    $ git status
On branch 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
│   ├── dev
│   └── master ├── objects
│   ├── 07 │   │   └── 71aea884dd394a7b12783d049f05b5599f41a4 (git blob object for c3) │   ├── 16 │   │   └── f9ec009e5568c435f473ba3a1df732d49ce8c3 (git blob object for c2) 
│   ├── 1a │   │   └── 42c7d883cd929afafa268850e139da74e72fc3 (git commit object for new c3) <= NEW │   ├── 21 │   │   └── 280bbd692007b5f635701cef0a31ba95ed5d94 (git tree object for conflict) <= NEW
│   ├── 3d │   │   └── 3095743da8025788f376069d9c07b9d867d5c1 (git tree object for c4) │   ├── 61 │   │   └── 8ce2788f58e3fb609e5666ab6c433f37423604 (git tree object for c5) │   ├── 71 │   │   └── 823caf53fc21b9909e073361dac6f9e3cfba96 (git commit object for c4) 
│   ├── 98 │   │   └── 3a0a8ef586ce632217931ebcb97d18c3f1e781 (git blob object for new c3) <= NEW
│   ├── a1 │   │   └── 03f673dd1b7c5727aa0ae0100419adc50e1b76 (git blob object for c4) │   ├── ae │   │   ├── 8f0444ccad90b277e3c51220c8d1f1af0cfba0 (git commit object for c1) │   │   └── 9304576a6ec3419b231b2b9c8e33a06f97f9fb (git blob object for c1) │   ├── b5 │   │   └── fab02de1c1f88003afeb7e98cf84a141bff039 (git tree object for c3) │   ├── b7 │   │   └── 19c3c104eefb9edef6b06d190e140f8af62377 (git commit object for c2) │   ├── c0 │   │   └── b072a3d368667939677b9315360631a100ecde (git tree object for c2) │   ├── c3 │   │   └── 6357109ce20af8f90df3c0dd0784e89408d707 (git blob object for c5) │   ├── ca │   │   └── 63078ddb21c6db42795ed3a20a867dee2d9ed8 (git commit object for c5) 
│   ├── d2 │   │   └── 7e4240f4faf17a95884f009416bfafd88a4572 (git commit object for c3) │   ├── e2 │   │   └── 061d2d7549cdd5cdeffa40308264cc17b956b9 (git tree object for new c3) <= NEW
│   ├── f1 │   │   └── 8c7b882bf09e79d96b692c31450cf59344fbf4 (git tree object for c1)
│   ├── f5 │   │   └── 7f64e9fadcf897efa1173509cd215908ec4186 (git blob object for conflict) <= NEW
│   ├── info │   └── pack └── refs ├── heads
│   ├── dev
│   └── master └── tags 31 directories, 44 files


Check the conflict objects.


    $ git cat-file -t 21280bb
tree

$ git cat-file -p 21280bb
100644 blob f57f64e9fadcf897efa1173509cd215908ec4186 test.txt

$ git cat-file -p f57f64
<<<<<<< HEAD c4 ======= c3 >>>>>>> d27e424 (c3)


Check more info.


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

$ cat .git/refs/heads/master
1a42c7d883cd929afafa268850e139da74e72fc3

$ cat .git/refs/heads/dev
ca63078ddb21c6db42795ed3a20a867dee2d9ed8

$ git ls-files -s
100644 983a0a8ef586ce632217931ebcb97d18c3f1e781 0 test.txt

$ git log --oneline --decorate --graph --all
* 1a42c7d (HEAD -> master) c3 * 71823ca c4 | * ca63078 (dev) c5 | * d27e424 c3 |/ * b719c3c c2 * ae8f044 c1



Use the 'git cherry-pick' command, git will rewrite the same commit with the new SHA-1 key (1a42c7d) on top of the current branch.