Monday 8 August 2022

Git strategies for applying bug fixes

$ mkdir test
 
$ cd test
 
$ git init
Initialised empty Git repository in /home/bojan/dev/test/.git/
 
$ git status
On branch master

No commits yet

nothing to commit (create/copy files and use "git add" to track)
 
$ touch foo.txt
 
$ vi foo.txt
 
foo.txt:
 
feature A {
   A.1
   A.2
   A.3
}
 
$ git status
On branch master

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)
    foo.txt

nothing added to commit but untracked files present (use "git add" to track)
 
$ git add foo.txt
 
$ git status
On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
    new file:   foo.txt
 
$ git commit -m "Added feature A"
[master (root-commit) ae68f9e] Added feature A
 1 file changed, 5 insertions(+)
 create mode 100644 foo.txt

 
 
Let's now create a feature branch for feature B. Let's assume we add a bug in its first implementation.
 
$ git checkout -b feature/B
Switched to a new branch 'feature/B'
 
$ vi foo.txt 
 
foo.txt:
 
feature A {
   A.1
   A.2
   A.3
}

feature B {
   B.1
   B.2 - bug
   B.3
}
 
$ git status
On branch feature/B
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:   foo.txt

no changes added to commit (use "git add" and/or "git commit -a")
 
$ git add foo.txt 
 
$ cat foo.txt
feature A {
   A.1
   A.2
   A.3
}

feature B {
   B.1
   B.2 - bug
   B.3
}
 
$ git commit -m "Added feature B"
[feature/B c2f2c7d] Added feature B
 1 file changed, 6 insertions(+)
 
$ git log
commit c2f2c7d39fb93b3fb45ec9ff384e0ebd5303253d (HEAD -> feature/B)
Author: Bojan Komazec <bojan.komazec@example.com>
Date:   Mon Aug 8 21:36:48 2022 +0100

    Added feature B

commit ae68f9ea4bf55f54a8f40831df5b980dc30e5c6e (master)
Author: Bojan Komazec <bojan.komazec@example.com>
Date:   Mon Aug 8 21:34:20 2022 +0100

    Added feature A
 
 
$ git rebase master
Current branch feature/B is up to date.
 
$ git checkout master
Switched to branch 'master'
 
$ git merge feature/B
Updating ae68f9e..c2f2c7d
Fast-forward
 foo.txt | 6 ++++++
 1 file changed, 6 insertions(+)

 
Let's assume we've now realized that there's a bug in the current implementation of feature B.
 
 
$ git log
commit c2f2c7d39fb93b3fb45ec9ff384e0ebd5303253d (HEAD -> master, feature/B)
Author: Bojan Komazec <bojan.komazec@example.com>
Date:   Mon Aug 8 21:36:48 2022 +0100

    Added feature B

commit ae68f9ea4bf55f54a8f40831df5b980dc30e5c6e
Author: Bojan Komazec <bojan.komazec@example.com>
Date:   Mon Aug 8 21:34:20 2022 +0100

    Added feature A
 
 
$ git revert c2f2c7d39fb93b3fb45ec9ff384e0ebd5303253d
[master cd72121] Revert "Added feature B"
 1 file changed, 6 deletions(-)
 
$ git log
commit cd721217e154dc74cad4037135c0ea2c0b898696 (HEAD -> master)
Author: Bojan Komazec <bojan.komazec@example.com>
Date:   Mon Aug 8 21:42:57 2022 +0100

    Revert "Added feature B"
    
    This reverts commit c2f2c7d39fb93b3fb45ec9ff384e0ebd5303253d.

commit c2f2c7d39fb93b3fb45ec9ff384e0ebd5303253d (feature/B)
Author: Bojan Komazec <bojan.komazec@example.com>
Date:   Mon Aug 8 21:36:48 2022 +0100

    Added feature B

commit ae68f9ea4bf55f54a8f40831df5b980dc30e5c6e
Author: Bojan Komazec <bojan.komazec@example.com>
Date:   Mon Aug 8 21:34:20 2022 +0100

    Added feature A
 
 
We now want to fix the bug so we create a new branch, B2, by branching off feature/B:
 
$ git checkout feature/B
Switched to branch 'feature/B'
 
$ git checkout -b feature/B2
Switched to a new branch 'feature/B2'
 
$ cat foo.txt
feature A {
   A.1
   A.2
   A.3
}

feature B {
   B.1
   B.2 - bug
   B.3
}
 
 
$ vi foo.txt 

foo.txt:

feature A {
   A.1
   A.2
   A.3
}

feature B {
   B.1
   B.2 - bug fixed
   B.3
}
 
 
$ git status
On branch feature/B2
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:   foo.txt

no changes added to commit (use "git add" and/or "git commit -a")
 
$ git commit -a -m "Fixed bug in feature B"
[feature/B2 29dbed4] Fixed bug in feature B
 1 file changed, 1 insertion(+), 1 deletion(-)
 
$ git status
On branch feature/B2
nothing to commit, working tree clean
 
$ cat foo.txt
feature A {
   A.1
   A.2
   A.3
}

feature B {
   B.1
   B.2 - bug fixed
   B.3
}

Before we merge feature branch to trunk, we first want to rebase it:
 
 
$ git rebase -i master
Auto-merging foo.txt
CONFLICT (content): Merge conflict in foo.txt
error: could not apply 29dbed4... Fixed bug in feature B

Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply 29dbed4... Fixed bug in feature B
 
 
$ vi foo.txt 

We're taking all changes from feature branch.

$ git add foo.txt 
 
$ git rebase --continue
[detached HEAD b86cff8] Fixed bug in feature B
 1 file changed, 7 insertions(+)
Successfully rebased and updated refs/heads/feature/B2.
 
$ git log
commit b86cff82118bb6af2bf10a4adf584e924acaaed0 (HEAD -> feature/B2)
Author: Bojan Komazec <bojan.komazec@example.com>
Date:   Mon Aug 8 21:47:55 2022 +0100

    Fixed bug in feature B

commit cd721217e154dc74cad4037135c0ea2c0b898696 (master)
Author: Bojan Komazec <bojan.komazec@example.com>
Date:   Mon Aug 8 21:42:57 2022 +0100

    Revert "Added feature B"
    
    This reverts commit c2f2c7d39fb93b3fb45ec9ff384e0ebd5303253d.

commit c2f2c7d39fb93b3fb45ec9ff384e0ebd5303253d (feature/B)
Author: Bojan Komazec <bojan.komazec@example.com>
Date:   Mon Aug 8 21:36:48 2022 +0100

    Added feature B

commit ae68f9ea4bf55f54a8f40831df5b980dc30e5c6e
Author: Bojan Komazec <bojan.komazec@example.com>
Date:   Mon Aug 8 21:34:20 2022 +0100

    Added feature A
 
$ git status
On branch feature/B2
nothing to commit, working tree clean
 
 
We can now merge feature branch into master:
 
 
$ git checkout master
Switched to branch 'master'
 
$ git status
On branch master
nothing to commit, working tree clean
 
$ git log
commit cd721217e154dc74cad4037135c0ea2c0b898696 (HEAD -> master)
Author: Bojan Komazec <bojan.komazec@example.com>
Date:   Mon Aug 8 21:42:57 2022 +0100

    Revert "Added feature B"
    
    This reverts commit c2f2c7d39fb93b3fb45ec9ff384e0ebd5303253d.

commit c2f2c7d39fb93b3fb45ec9ff384e0ebd5303253d (feature/B)
Author: Bojan Komazec <bojan.komazec@example.com>
Date:   Mon Aug 8 21:36:48 2022 +0100

    Added feature B

commit ae68f9ea4bf55f54a8f40831df5b980dc30e5c6e
Author: Bojan Komazec <bojan.komazec@example.com>
Date:   Mon Aug 8 21:34:20 2022 +0100

    Added feature A
 
$ git merge feature/B2
Updating cd72121..b86cff8
Fast-forward
 foo.txt | 7 +++++++
 1 file changed, 7 insertions(+)
 
$ git status
On branch master
nothing to commit, working tree clean
 
$ cat foo.txt
feature A {
   A.1
   A.2
   A.3
}

feature B {
   B.1
   B.2 - bug fixed
   B.3
}



We assumed here that we had the original feature branch available. Alternatively, we could have created a new branch off the master, reverse the reverse commit, apply the fix and then merge it back to master.