#90DaysOfDevOps - Day 11: Advance Git & GitHub for DevOps Engineers: Part-2

Introduction

Welcome to Day 11 of the 90DaysDevOps Challenge! In Part 2, we're delving into advanced Git techniques: git stash, git cherrypick, and conflict resolution. No long lectures here – just hands-on exercises. Picture effortlessly moving changes from dev to production using stash and cherrypick, and mastering conflict resolution. Let's own Day 11!

git stash

Git Stash Command - Scaler Topics

Imagine you're working on a project using Git, which keeps track of your code changes. Sometimes, you need to temporarily put aside your current changes and work on something else.

Think of Git stash like a magic box. When you use it, your ongoing changes are put into this box so you can switch to a different task. But the cool thing is, even after you take those changes out of the box and use them, the changes are still kept safely inside.

This is helpful when you're fixing a problem. You can put your changes in the box, then test if your fix works on different parts of the project without messing up everything. This is better than mixing all your changes together, which can be confusing.

So, when you're ready to share your fix, you know it works because you tried it in different places. And when you ask others to add your fix to their work, you're sure you're only giving them what they need, not extra stuff.

Commands

git stash stash the changes that have been added to your index (staged changes) and changes made to files that are currently tracked by Git (unstaged changes).

git stash list view the stash list

git stash pop removes the most recent changes from the stash and reapplies them in the working copy

git stash apply reapplies the changes in the working copy without removing the changes from the stash

git stash clear deletes all stashes

git cherrypick

How To Cherry Pick Git Commits | When & How to use a Git Cherry Pick  Commit? – Junos Notes

At times, there's a need to move a specific update from one branch to another without including all the other changes from the starting branch. To achieve this, Git offers a command called cherry-pick.

In Git, cherry-pick involves selecting a single commit from one branch and adding it to a different one. This stands in contrast to methods like merge and rebase, which usually involve adding multiple commits to another branch.

Command

git cherry-pick <commit_hash> pick the commit associated with the specified commit hash to the current branch.

Git conflicts and resolution

Merging Changes: In Git, merging means adding changes from one workspace (branch) to another. Think of branches like separate workspaces.

Using Git makes merging easy. Usually, it figures out how to mix changes. But sometimes, when changes clash (like two people editing the same part of a file), you need to help Git decide. For example, if two people change the same lines in a file, Git can't choose. It's like two people changing a sentence differently. Git marks this as a "conflict," and you fix it before moving on.

Handling Conflicts: When there's a problem, find out what's up. Did others mess with your work? Delete it? Make files with the same name?

Git says there are issues by showing conflicts. You see this with "git status." It's like a flag to sort things out.

Fixing Conflicts: When there's a conflict, open the file in your code editor. Git guides you with "<<<<<<< HEAD" and ">>>>>>> [other/branch/name]" around the problem. After "<<<<<<< HEAD" is your version. The second marker shows where changes came from. "=====" splits the conflicts. It's like signs for the problem.

Now, fix these lines. The file should look how you want. Sometimes, talk with your teammate who made the conflicting changes to pick the right code. It might be yours, theirs, or a mix.

Task 1 - git stash

  • Create a new branch and make some changes to it.

  • Use git stash to save the changes without committing them.

  • Switch to a different branch, make some changes, and commit them.

  • Use git stash pop to bring the changes back and apply them on top of the new commits.

    We will create "feature-1" branch and add a single commit. Then we make two changes.

    NOTE: git stash doesn't work when new files are created. It only works on modified files.

      #switch to main branch
      ubuntu@~/Devops$: git checkout main 
      Already on 'main'
      Your branch is up to date with 'origin/main'.
      #create and switch to new branch feature-1
      ubuntu@~/Devops$: git checkout -b feature-1
      Switched to a new branch 'feature-1'
      ubuntu@~/Devops$: mkdir feature-1
      ubuntu@~/Devops$: cd feature-1/
      ubuntu@~/Devops/feature-1$: echo "First functionality of feature 1" > feature1.txt
      #stage and commit the changes
      ubuntu@~/Devops$: git add .
      ubuntu@~/Devops$: git commit -m "Added first functionality to feature 1"
      [feature-1 485b829] Added first functionality to feature 1
       1 file changed, 1 insertion(+)
       create mode 100644 feature-1/feature1.txt
    
      #add few more changes
      ubuntu@~/Devops/feature-1$: echo "Second functionality of feature 1" >> feature1.txt 
      ubuntu@~/Devops/feature-1$: echo "Final functionality of feature 1" >> feature1.txt 
      ubuntu@~/Devops/feature-1$: cat feature1.txt 
      First functionality of feature 1
      Second functionality of feature 1
      Final functionality of feature 1
    

    Now that we have modified the "feature-1.txt" file, we will use git stash and view the results.

      #check the status of repository
      ubuntu@~/Devops/feature-1$: git status
      On branch feature-1
      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:   feature1.txt
    
      no changes added to commit (use "git add" and/or "git commit -a")
    
      #use git stash
      ubuntu@~/Devops/feature-1$: git stash
      Saved working directory and index state WIP on feature-1: 485b829 Added first functionality to feature 1
    
      #view the status of repository after git stash
      #the changes have been added to stash
      ubuntu@~/Devops/feature-1$: git status
      On branch feature-1
      nothing to commit, working tree clean
    
      #view the changes present in stash
      ubuntu@~/Devops/feature-1$: git stash show
       feature-1/feature1.txt | 2 ++
       1 file changed, 2 insertions(+)
    

    We switch to the "dev" branch and add a change.

      ubuntu@~/Devops/feature-1$: cd ..
      ubuntu@~/Devops$: git checkout dev 
      Switched to branch 'dev'
      ubuntu@~/Devops$: git status
      On branch dev
      nothing to commit, working tree clean
      ubuntu@~/Devops$: echo "This is bug fix" >> git/version02.txt 
      ubuntu@~/Devops$: cat git/version02.txt 
      This is feature 2 implementation
      This is feature 3 implementation
      Bug found in feature 2. Fixing the bug
      This is bug fix
      ubuntu@~/Devops$: git add . && git commit -m "Fixed a bug"
      [dev 119ada7] Fixed a bug
       1 file changed, 1 insertion(+)
    
      #use git stash pop.
      #throws an error stating that there is conflict
      ubuntu@~/Devops$: git stash pop
      CONFLICT (modify/delete): feature-1/feature1.txt deleted in Updated upstream and modified in Stashed changes. Version Stashed changes of feature-1/feature1.txt left in tree.
      The stash entry is kept in case you need it again.
      #resolve the conflict by creating feature-1/feature1.txt
      ubuntu@~/Devops$: touch feature-1/feature1.txt
      #use git stash pop again
      ubuntu@~/Devops$: git stash pop
      On branch dev
      Changes to be committed:
        (use "git restore --staged <file>..." to unstage)
              new file:   feature-1/feature1.txt
    
      Dropped refs/stash@{0} (f89cfb8ab50bff7f79a06007fcf1b48aabd57609)
      #check the changes from stash
      ubuntu@~/Devops$: cat feature-1/feature1.txt 
      First functionality of feature 1
      Second functionality of feature 1
      Final functionality of feature 1
      #verify whether there are any more changes in stash
      ubuntu@~/Devops$: git stash show
      No stash entries found.
    

    After we resolved the conflict, we were able to remove and use the changes that were stashed. After the git stash pop, the changes are staged to the "dev" branch.

Task 2 - git rebase

  • In version01.txt of the development branch add the below lines after “This is the bug fix in development branch” that you added in Day10 and reverted to this commit.

  • Line2>> After bug fixing, this is the new feature with minor alterations”

    Commit this with the message “ Added feature2.1 in development branch”

  • Line3>> This is the advancement of the previous feature

    Commit this with the message “ Added feature2.2 in development branch”

  • Line4>> Feature 2 is completed and ready for release

    Commit this with the message “ Feature2 completed”

  • All these commits messages should be reflected in the Production branch too which will come out from the main branch (Hint: try rebase)

      #switch to dev branch
      ubuntu@~/Devops$: git checkout dev
      Switched to branch 'dev'
      #adding first change
      ubuntu@~/Devops$: echo "This is the bug fix in development branch" > version01.txt
      #stage and commit the change
      ubuntu@~/Devops$: git add . && git commit -m "Fixed bug"
      [dev b6322b2] Fixed bug
       1 file changed, 1 insertion(+)
       create mode 100644 version01.txt
      #adding next change
      ubuntu@~/Devops$: echo "This is new feature with minor alterations" >> version01.txt 
      #stage and commit the change
      ubuntu@~/Devops$: git add . && git commit -m "Added feature2.1"
      [dev 5f34f31] Added feature2.1
       1 file changed, 1 insertion(+)
      #adding next change
      ubuntu@~/Devops$: echo "This is advancement of the previous feature" >> version01.txt
      #stage and commit the change
      ubuntu@~/Devops$: git add . && git commit -m "Added feature2.2"
      [dev c514680] Added feature2.2
       1 file changed, 1 insertion(+)
      #adding final change
      ubuntu@~/Devops$: echo "Feature 2 is ready for releas" >> version01.txt 
      #stage and commit the change
      ubuntu@~/Devops$: git add . && git commit -m "Feature 2 completed"
      [dev 52cfe87] Feature 2 completed
       1 file changed, 1 insertion(+)
      #view the contents
      ubuntu@~/Devops$: cat version01.txt 
      This is the bug fix in development branch
      This is new feature with minor alterations
      This is advancement of the previous feature
      Feature 2 is ready for releas
      #view the commit history
      ubuntu@~/Devops$: git log --oneline 
      52cfe87 (HEAD -> dev) Feature 2 completed
      c514680 Added feature2.2
      5f34f31 Added feature2.1
      b6322b2 Fixed bug
      7245537 Completed feature 1
      119ada7 Fixed a bug
      dc8e16c Revert "Added new feature"
      3d2230b Fixed bug in feature 2
      2b1b7ce Added feature 3
      d7a3075 Added feature 2
      df4abbb (origin/dev) Added new feature
      23ac50c Added day 2 file
      0983dd8 Initial commit
    

Now that we have added changes to the "dev" branch, we proceed to add them to a new "prod" (production) branch using git rebase

#switch to "main" branch
ubuntu@~/Devops$: git checkout main 
Switched to branch 'main'
Your branch is up to date with 'origin/main'.
#create and switch to new "prod" branch
ubuntu@~/Devops$: git checkout -b prod
Switched to a new branch 'prod'
#check the commit history before rebase
ubuntu@~/Devops$: git log --oneline 
27f73f4 (HEAD -> prod, origin/main, origin/HEAD, main, feature) Fixed a bug in feature
545c4f4 Added new feature
3d2230b Fixed bug in feature 2
2b1b7ce Added feature 3
d7a3075 Added feature 2
df4abbb (origin/dev) Added new feature
23ac50c Added day 2 file
0983dd8 Initial commit
#merge the changes from "dev" branch to "prod" using git rebase
ubuntu@~/Devops$: git rebase dev
Successfully rebased and updated refs/heads/prod.
ubuntu@~/Devops$: git log --oneline 
27f73f4 (HEAD -> prod) Fixed a bug in feature
545c4f4 Added new feature
52cfe87 (dev) Feature 2 completed
c514680 Added feature2.2
5f34f31 Added feature2.1
b6322b2 Fixed bug
7245537 Completed feature 1
119ada7 Fixed a bug
dc8e16c Revert "Added new feature"
3d2230b Fixed bug in feature 2
2b1b7ce Added feature 3
d7a3075 Added feature 2
df4abbb (origin/dev) Added new feature
23ac50c Added day 2 file
0983dd8 Initial commit

Task 3 - git cherry-pick

  • In the Production branch Cherry pick Commit “Added feature2.2 in development branch” and add the below lines in it:

  • The line to be added after Line3>> This is the advancement of the previous feature

  • Line 4>>Added a few more changes to make it more optimized.

  • Commit: Optimized the feature

We will use git cherry-pick command to pick a commit from the "dev" branch to the "prod" branch and then commit a few changes to the "prod" branch.

#switch to "prod" branch
ubuntu@~/Devops$: git checkout prod 
Already on 'prod'

#view the commit log to get the commit id hash
ubuntu@~/Devops$: git log --oneline 
27f73f4 (HEAD -> prod) Fixed a bug in feature
545c4f4 Added new feature
52cfe87 (dev) Feature 2 completed
c514680 Added feature2.2
5f34f31 Added feature2.1
b6322b2 Fixed bug
7245537 Completed feature 1
119ada7 Fixed a bug
dc8e16c Revert "Added new feature"
3d2230b Fixed bug in feature 2
2b1b7ce Added feature 3
d7a3075 Added feature 2
df4abbb (origin/dev) Added new feature
23ac50c Added day 2 file
0983dd8 Initial commit

#cherry-pick the required commit
ubuntu@~/Devops$: git cherry-pick c514680
Auto-merging version01.txt
CONFLICT (content): Merge conflict in version01.txt
error: could not apply c514680... Added feature2.2
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".

#view status of the repo for conflicts
ubuntu@~/Devops$: git status
On branch prod
You are currently cherry-picking commit c514680.
  (fix conflicts and run "git cherry-pick --continue")
  (use "git cherry-pick --skip" to skip this patch)
  (use "git cherry-pick --abort" to cancel the cherry-pick operation)

Unmerged paths:
  (use "git add <file>..." to mark resolution)
        both modified:   version01.txt

no changes added to commit (use "git add" and/or "git commit -a")

#update the file contents and resolve the conflict
ubuntu@~/Devops$: vim version01.txt 

#continue with cherry-pick
ubuntu@~/Devops$: git cherry-pick --continue 
U       version01.txt
error: Committing is not possible because you have unmerged files.
hint: Fix them up in the work tree, and then use 'git add/rm <file>'
hint: as appropriate to mark resolution and make a commit.
fatal: Exiting because of an unresolved conflict.

#the error says to use git add
ubuntu@~/Devops$: git add .
ubuntu@~/Devops$: git status
On branch prod
You are currently cherry-picking commit c514680.
  (all conflicts fixed: run "git cherry-pick --continue")
  (use "git cherry-pick --skip" to skip this patch)
  (use "git cherry-pick --abort" to cancel the cherry-pick operation)

Changes to be committed:
        modified:   version01.txt

#finally continue cherry-pick
ubuntu@~/Devops$: git cherry-pick --continue 
[prod 1171db7] Added feature2.2
 Date: Fri Aug 18 03:40:51 2023 +0000
 1 file changed, 1 deletion(-)

#view the commit log to verify the cherry-pick commit
ubuntu@~/Devops$: git log --oneline 
1171db7 (HEAD -> prod) Added feature2.2
27f73f4 Fixed a bug in feature
545c4f4 Added new feature
52cfe87 (dev) Feature 2 completed
c514680 Added feature2.2
5f34f31 Added feature2.1
b6322b2 Fixed bug
7245537 Completed feature 1
119ada7 Fixed a bug
dc8e16c Revert "Added new feature"
3d2230b Fixed bug in feature 2
2b1b7ce Added feature 3
d7a3075 Added feature 2
df4abbb (origin/dev) Added new feature
23ac50c Added day 2 file
0983dd8 Initial commit

#continue further by adding more changes
ubuntu@~/Devops$: echo "This is the advancement of previous feature" >> version01.txt 
ubuntu@~/Devops$: echo "Added few more changes to make it more optimized" >> version01.txt 

#stage and commit the changes
ubuntu@~/Devops$: git add . && git commit -m "Optimized the feature"
[prod ea6dbfa] Optimized the feature
 1 file changed, 2 insertions(+)

Conclusion

In conclusion, Day 11 of the 90DaysDevOps Challenge equips you with advanced Git techniques: git stash, git cherrypick, and conflict resolution. These skills streamline moving changes between branches and mastering conflict resolution. Your ability to navigate complex version control scenarios has taken a leap. As you continue your DevOps journey, practice and apply these skills for smoother development.

"🌱 Keep learning, and spread the knowledge to inspire others. 🚀💡"

Go back to the main page