#90DaysOfDevOps - Day 10: Advance Git & GitHub for DevOps Engineers.
Introduction
Today is the 10th day of the 90DaysDevOps challenge, where we're diving into advanced Git & GitHub for DevOps Engineers. We'll be exploring things like git branching (which is like making different paths for our work), git revert and reset (fixing mistakes), git rebase (kind of like rearranging our work), and git merge (mixing different parts of our work together).
Then, we'll get our hands busy with some practice. We'll make a new file, change it a lot, and save our changes multiple times. We'll also undo some of the changes we made. Plus, we'll add new paths for our work, make changes in one path, and bring those changes into the main path. We'll even try out git rebase to see what happens. Ready to start this adventure? Let's go!
Git branching
Think of branches as separate lanes for developing. They're like asking for a new space to work on things, with its own area for changes and history. When you use branches for different features, you can work on them at the same time without messing up the main work. This keeps the main part clean from any uncertain changes.
Branches allow you to develop features, fix bugs, or safely experiment with new ideas in a contained area of your repository.
Some common commands
git branch
List all the branches in the repository
git branch <branch>
Creates a new branch called <branch> but does not checks out the new branch.
git branch -d <branch>
Deletes a branch. If there are unmerged changes, Git does not allow you to delete it.
git branch -D <branch>
Forces delete the branch, even if there are unmerged changes. Execute this command when you are sure to delete it permanently.
git branch -m <branch>
Moves or renames the current branch to <branch>.
git branch -a
Lists all the remote branches.
git revert and git reset
git revert: Git revert is used to create a new commit that undoes the changes made by a specific commit or a range of commits. It's a safe way to undo changes without rewriting history. The commit history will show the original commit followed by a new commit that reverses those changes. The original commit remains in history.
Identify the commit you want to revert. You can find the commit hash using
git log
.Use the following command to create a new commit that undoes the changes:
git revert <commit_hash>
Git will open an editor for you to provide a commit message. Save and close the editor to create the revert commit.
git reset: Git reset is used to move the current branch pointer and the staging area to a specified commit. It can be used to "rewind" the history, but it's important to note that it should be used with caution, especially if the commits have been pushed to a remote repository.
There are different modes of git reset
:
Soft reset (
git reset --soft <commit_hash>
): Moves the branch pointer to the specified commit without changing the staging area or working directory. The changes in the "reset" commits will appear as uncommitted changes.Mixed reset (default) (
git reset <commit_hash>
orgit reset --mixed <commit_hash>
): Moves the branch pointer and updates the staging area to match the specified commit, but does not change the working directory. The changes from the "reset" commits will appear as uncommitted changes.Hard reset (
git reset --hard <commit_hash>
): Moves the branch pointer, updates the staging area, and changes the working directory to match the specified commit. Be cautious with this mode as it discards all changes after the reset point.git reset HEAD~n
is a variation of thegit reset
command that allows you to move the branch pointer to a specified number of commits back in the history. Then
inHEAD~n
represents the number of commits you want to move back.
git merge and git rebase
git merge: It is the process of combining the changes from one branch into another. Here's how you would merge your changes from a feature branch (let's call it feature-branch
) into the main branch (main
or master
).
Check out the main branch:
git checkout main
Merge the feature-branch into the main:
git merge feature-branch
This will create a new commit on the main branch that represents the merge of the feature branch.
When you merge a branch into another, you create a new commit (merge commit) that has two parent commits: the last commit on the main branch and the last commit on the feature branch. This creates a clear indication in the commit history that a merge has taken place.
git rebase: It is a process that moves the entire history of one branch onto another, essentially replaying the changes from the source branch on top of the target branch.
Checkout the feature branch**:**
git checkout feature-branch
Rebase the feature branch onto the main:
git rebase main
This will apply your changes from the feature branch on top of the latest changes on the main branch.
Rebasing rewrites the commit history of the feature branch. It creates new commits with new hashes, as the original commits are replayed on top of the target branch. This can result in a cleaner, linear commit history without merging commits.
Task 1
Add a text file called version01.txt inside the Devops/Git/ with “This is the first feature of our application” written inside. This should be in a branch coming from master
, [hint try git checkout -b dev
], switch to dev
branch ( Make sure your commit message will reflect as "Added new feature"). [Hint use your knowledge of creating branches and Git commit command]
- version01.txt should reflect at the local repo first followed by the Remote repo for review. [Hint use your knowledge of Git push and git pull commands here]
Add a new commit in dev
branch after adding below mentioned content in Devops/Git/version01.txt: While writing the file make sure you write these lines
1st line>> This is the bug fix in development branch
Commit this with the message “ Added feature2 in development branch”
2nd line>> This is gadbad code
Commit this with the message “ Added feature3 in the development branch
3rd line>> This feature will gadbad everything from now.
Commit with the message “ Added feature4 in the development branch
Restore the file to a previous version where the content should be “This is the bug fix in the development branch” [Hint use git revert or reset according to your knowledge]
Let's execute
We had already created "Devops" GitHub repo in the previous day's task. We will continue using the same.
Assuming you already have the "Devops" repo as a local repository.
#create a new and shift to the new branch "dev"
ubuntu@~/Devops$: git checkout -b dev
Switched to a new branch 'dev'
#create new file "git/version01.txt" and add content to the same file
ubuntu@~/Devops$: echo "This is the first feature of our application" > git/version01.txt
#view the content
ubuntu@~/Devops$: cat git/version01.txt
This is the first feature of our application
#move the changes to staging area
ubuntu@~/Devops$: git add .
#commit the changes with suitable message
ubuntu@~/Devops$: git commit -m "Added new feature"
[dev df4abbb] Added new feature
1 file changed, 1 insertion(+)
create mode 100644 git/version01.txt
Now that we have committed the changes to "version01.txt" file, we will now push the changes to GitHub.
#push the changes of branch dev to GitHub
ubuntu@~/Devops$: git push origin dev
Enter passphrase for key '/home/ubuntu/.ssh/id_ed25519':
Enumerating objects: 6, done.
Counting objects: 100% (6/6), done.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (4/4), 398 bytes | 398.00 KiB/s, done.
Total 4 (delta 0), reused 0 (delta 0), pack-reused 0
remote:
remote: Create a pull request for 'dev' on GitHub by visiting:
remote: https://github.com/pka2412/Devops/pull/new/dev
remote:
To github.com:pka2412/Devops.git
* [new branch] dev -> dev
We will continue adding more changes to "version01.txt" file.
ubuntu@~/Devops$: git branch
* dev
main
#add new contents to the file
ubuntu@~/Devops$: echo "This is bug fix" >> git/version01.txt
#view the contents
ubuntu@~/Devops$: cat git/version01.txt
This is the first feature of our application
This is bug fix
#move the changes to staging area
ubuntu@~/Devops$: git add -A
#commit the changes
ubuntu@~/Devops$: git commit -m "Added feature 2"
[dev 597a10a] Added feature 2
1 file changed, 1 insertion(+)
#add new contents to the file
ubuntu@~/Devops$: echo "This is gadbad code" >> git/version01.txt
#view the contents
ubuntu@~/Devops$: cat git/version01.txt
This is the first feature of our application
This is bug fix
This is gadbad code
#move the changes to staging area
ubuntu@~/Devops$: git add -A
#commit the changes
ubuntu@~/Devops$: git commit -m "Added feature 3"
[dev 0163f58] Added feature 3
1 file changed, 1 insertion(+)
#add new contents to the file
ubuntu@~/Devops$: echo "This feature will gadbad everything now" >> git/version01.txt
#view the contents
ubuntu@~/Devops$: cat git/version01.txt
This is the first feature of our application
This is bug fix
This is gadbad code
This feature will gadbad everything now
#move the changes to staging area
ubuntu@~/Devops$: git add -A
#commit the changes
ubuntu@~/Devops$: git commit -m "Added feature 4"
[dev d6c75a9] Added feature 4
1 file changed, 1 insertion(+)
Restore the file to a previous version where the content should be “This is the bug fix in the development branch”. First we get the commit id of the commit.
#get the commit id from the log
ubuntu@~/Devops$: git log --oneline
d6c75a9 (HEAD -> dev) Added feature 4
0163f58 Added feature 3
597a10a Added feature 2
df4abbb (origin/dev) Added new feature
23ac50c (origin/main, origin/HEAD, main) Added day 2 file
0983dd8 Initial commit
#reset the branch to commit id "df4abbb" and also discard the changes using "--hard"
ubuntu@~/Devops$: git reset df4abbb --hard
HEAD is now at df4abbb Added new feature
#view the content. We see only first line is present.
ubuntu@~/Devops$: cat git/version01.txt
This is the first feature of our application
#view the log
ubuntu@~/Devops$: git log --oneline
df4abbb (HEAD -> dev, origin/dev) Added new feature
23ac50c (origin/main, origin/HEAD, main) Added day 2 file
0983dd8 Initial commit
Task 2
Add some changes to
dev
branch and merge that branch inmain
We will add around three changes to the "dev" branch.
#create new git/version02.txt file with some content ubuntu@~/Devops$: echo "This is feature 2 implementation" > git/version02.txt ubuntu@~/Devops$: cat git/version02.txt This is feature 2 implementation #stage and commit the changes ubuntu@~/Devops$: git add -A ubuntu@~/Devops$: git commit -m "Added feature 2" [dev d7a3075] Added feature 2 1 file changed, 1 insertion(+) create mode 100644 git/version02.txt #next change ubuntu@~/Devops$: echo "This is feature 3 implementation" >> git/version02.txt ubuntu@~/Devops$: cat git/version02.txt This is feature 2 implementation This is feature 3 implementation #stage and commit the changes ubuntu@~/Devops$: git add -A ubuntu@~/Devops$: git commit -m "Added feature 3" [dev 2b1b7ce] Added feature 3 1 file changed, 1 insertion(+) #next change ubuntu@~/Devops$: echo "Bug found in feature 2. Fixing the bug" >> 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 #stage and commit the changes ubuntu@~/Devops$: git add -A ubuntu@~/Devops$: git commit -m "Fixed bug in feature 2" [dev 3d2230b] Fixed bug in feature 2 1 file changed, 1 insertion(+) #view the log to see the commits ubuntu@~/Devops$: git log --oneline 3d2230b (HEAD -> dev) Fixed bug in feature 2 2b1b7ce Added feature 3 d7a3075 Added feature 2 df4abbb (origin/dev) Added new feature 23ac50c (origin/main, origin/HEAD, main) Added day 2 file 0983dd8 Initial commit
After adding changes to "dev" branch, we will merge them to the "main" branch and view the commit history.
#switch to "main" branch" ubuntu@~/Devops$: git checkout main Switched to branch 'main' Your branch is up to date with 'origin/main'. #merge the changes from "dev" to "main" branch ubuntu@~/Devops$: git merge dev Updating 23ac50c..3d2230b Fast-forward git/version01.txt | 1 + git/version02.txt | 3 +++ 2 files changed, 4 insertions(+) create mode 100644 git/version01.txt #view the log to see the commits ubuntu@~/Devops$: git log --oneline 3d2230b (HEAD -> main, dev) Fixed bug in feature 2 2b1b7ce Added feature 3 d7a3075 Added feature 2 df4abbb (origin/dev) Added new feature 23ac50c (origin/main, origin/HEAD) Added day 2 file 0983dd8 Initial commit
After merging the "dev" to the "main" branch, we see that all the commits/changes that were made in the "dev" branch are now present in the "main" branch.
As a practice try git rebase too, and see what difference you get
Create a new branch "feature" and add two changes to the branch.
#create a new and switch to the new branch "feature" ubuntu@~/Devops$: git checkout -b feature Switched to a new branch 'feature' #add first change ubuntu@~/Devops$: echo "This is new feature implementation" > git/feature.txt ubuntu@~/Devops$: cat git/feature.txt This is new feature implementation #stage and commit the change ubuntu@~/Devops$: git add -A ubuntu@~/Devops$: git commit -m "Added new feature" [feature 800d30f] Added new feature 1 file changed, 1 insertion(+) create mode 100644 git/feature.txt #add next change ubuntu@~/Devops$: echo "Fix bug in the feature" > git/feature.txt ubuntu@~/Devops$: cat git/feature.txt Fix bug in the feature #stage and commit the change ubuntu@~/Devops$: git add -A ubuntu@~/Devops$: git commit -m "Fixed a bug in feature" [feature 92f0632] Added new feature 1 file changed, 1 insertion(+) create mode 100644 git/feature.txt
Now perform rebase "feature" to the "main" branch.
#view the log before rebase ubuntu@~/Devops$: git log --graph --oneline * 92f0632 (HEAD -> feature) Fixed a bug in feature * 800d30f Added new feature * 3d2230b (main, dev) Fixed bug in feature 2 * 2b1b7ce Added feature 3 * d7a3075 Added feature 2 * df4abbb (origin/dev) Added new feature * 23ac50c (origin/main, origin/HEAD) Added day 2 file * 0983dd8 Initial commit #switch to main branch ubuntu@~/Devops$: git checkout main Switched to branch 'main' Your branch is ahead of 'origin/main' by 4 commits. (use "git push" to publish your local commits) #rebase feature to main branch ubuntu@~/Devops$: git rebase feature Successfully rebased and updated refs/heads/main. ubuntu@~/Devops$: git log --all --decorate --oneline --graph * 92f0632 (HEAD -> main, feature) Fixed a bug in feature * 800d30f Added new feature * 3d2230b (dev) Fixed bug in feature 2 * 2b1b7ce Added feature 3 * d7a3075 Added feature 2 * df4abbb (origin/dev) Added new feature * 23ac50c (origin/main, origin/HEAD) Added day 2 file * 0983dd8 Initial commit
Conclusion
To sum up, Git's branching, reverting, resetting, rebasing, and merging features are vital tools for organized and collaborative development. Branching lets you work on multiple tasks in isolation while reverting and resetting help fix mistakes and backtrack when needed. Merging and rebasing integrate changes, with merging creating clear merge points and rebasing offering a linear history.
Our hands-on exercises demonstrated the practical application of these concepts. Creating files, branching for features, and merging changes emphasized the value of Git's capabilities. In collaborative settings, these skills foster efficient teamwork and conflict-free development.
"🌱 Keep learning, and spread the knowledge to inspire others. 🚀💡"