Above shows two different GIT timelines that will and will not merge properly!
The term “Fast-Forward” merge is analogous to Fast Forwarding a movie to the good part, as GIT does not care about the filler content that its moving past (Commit history of second branch), as long as there is none of the boring part overlapping the good part as that would make the movie worthless if the boring part is mixed into the good parts! Right? Right!
Note – The end of this post is a train wreck of attempting to fix a merge conflict off the cuff, and that is a road I learned you don’t want to go down, so there will be a follow up post to address how to properly handle merge conflicts and unified diff / code review!
Otherwise there is about all you need to know about GIT in here for exam day, but I kind of buried myself in the merge conflict commit timeline, and reset the GIT Head but that isn’t how you resolve a merge conflict but rather recover from one with major data loss
This is better explained through a branching picture I drew regarding “GitOps”:
This shows how the Master Branch is likely “checked out” while the Dev and Testing branches are going through their phases, as any “Commits” on the Master during this timeline would create a merge conflict when doing that last pull, and would need to be fixed by manually removing the changes made to the previous commit until it matches where it first split off and then it would properly merge on the last Pull Request.
Before getting into Push / Pull / Clone / Etc, I want to hammer home some terminology
GIT is free and open source, and created by the father of Linux in fact, Linus Torvalds.
GIT is comprised of a tree like structure (not referring to branches) in 3 main structures:
- Local Workspace – Your local machine with a GIT Repository on it
- Staging Area – The intermediary area before making a commit to the GIT Timeline
- Head / Local Repo – The current branch you are working with GIT / where your commits are stored for that branch timeline
In this Local Repository / Workspace there are 4 phases a file will be in if it is stored within the GIT Repository on your local workspace, like files saved but not tracked by GIT, these different GIT stages and their meaning is broken down here:
- Untracked – When a file is saved to a Git directory, but has not been added to Tracking via Staging / Commit of the file, which is not a problem if you don’t want that file tracked / part of the version control (like a temp file or password file), however to add it to tracking you do just that with “git add” command
- Unmodified – This means the file is tracked, but has no updates to it, “Staged” files will return back to an Unmodified state after doing a “Commit” on it (until you make changes to the file again)
- Modified – A tracked file has changes detected by Git, and it show “Modified” is its polite way of saying you need to stage and commit the file, or remove it from Git Tracking, which can get complicated (more on that below), need to “git add” file to stage it
- Staged – This is where a file change is added to the “Git Index” from doing a “git add” to stage the file, and a “git commit (file) -m “This is a required commit message” to update the repository / branch and the file will turn back to the Unmodified status
Below this graphic shows essential which action leads to which GIT status:
If your familiar with GIT the top one might confuse you, as how does both a Staged and completely Untracked file both go to “Unmodified” status, however this is because an Untracked file must be staged / commited to GIT which lands it in Unmodified status.
A visual reason of why it is a good idea to commit often, or check out Master Branches:
This shows my local GIT repo is clean, however it also is telling me to “Push” my local commits to the remote repo this master branch was cloned from, as if myself and another person both had the same copy of the Master Branch and I now push 3 new commits out to GitHub to update the Main Master Branch – The other person is going to run into a Merge Conflict when trying to “Push” their updated Master Branch.
Before getting into that though, a bit more terminology for GIT on exam day
GIT is an SVC (Software Version Control) that comes in two flavors of commands, “Porcelain” commands which are the user friendly add / commit / status / etc commands, then there is “Plumbing” commands which really get into the nuts and bolts of GIT and are not covered on the DEVASC.
For an example of GIT Plumbing, take LinkedIns GIT skills quiz, that is basically all plumbing commands / operations which is interesting to see but makes zero sense to me.
That being said, we will look at the Porcelain flavor commands a bit more here!
For example in my previous Ansible Lab I thought of just doing a “git clone” from my GitHub of my usual Master Branch, but I am actually going to clear that out, and initialize a local GIT Repository and start a new Master Branch on GitHub and look at created and merging some non-Master branches but first I must ditch the current local repo with the following:
This was a bit tricky, but I found if you just remove the .git, its no longer a repo:
It was not shown under “ls -a” either, so this is good to delete this folder entirely:
Note – This process will remove the GIT Repository entirely locally, so be sure it is pushed to a remote SVC service like GitHub, as this nukes the Local Repo!
Though I planned to nuke this one, as I’d like to start using my DevNet_Projects GitHub that I have yet to push a branch out to, so I will do that now as it is empty as can about be:
I could not believe that showed 8 months, its like 2020 just flew by! Time to start using this Repo since its been patiently waiting since February of this year:
Whether its a “Push” / “Clone” / “Pull” from GitHub you will want to copy the address from the drop down “Code” button on the GitHub Repo page (make sure you have the right repo)!
(I actually ran into some issues of syncing the local and remote repo, so I took the opportunity now to actually shorten the name of my repo’s as seen here):
This is one thing I really like about GitHub, its simple help makes it hard not to understand how to work with it, even when I had very limited knowledge, so I copy and paste that:
And just as fast I found something I don’t love at all, I needed to disable my 2-FA on my account for it to accept my credentials to push a new branch (this was the issue with the other folder as well but I needed to shorten that name anyways).
Well this is just sad, after re-enabling 2-FA I once again cannot Push to my Repo:
There has to be a way to make 2-FA work with Public Repo’s, I cannot believe there is a trade off in security for ability to work with your own repository – I will update regarding that.
HOWEVER – We do now have a new GIT Repo finally to discuss on GitHub:
More like “2-FA push test FAIL!” I must be missing something there, I will play with my cloning and pushing my loopedback repo and see if it does the same, I am wondering if the main Repo has to be “cloned” from GitHub for it to accept inbound updates.
Anyways. my point I was getting to is demonstrated in some of those screen snips:
- If you “git clone” you are cloning and over-writing an existing repo when you push to it, so you will want to be careful about pushing a commit back up to the Master Branch, its for this reason you’d probably want to push to different branches to first merge then finally merge to the Master Branch itself with all changes at once
- If you mess up and want to remove the remote repo tracking, use “git remote rm (branch)” and use “git remote -v” to verify nothing shows up as linked to your local repo
One important point on doing a “git init” and creating a local repo – You will need to configure yourself as a GIT user with the commands “git config –global user.name”something”” and “git config –global user.email “email@example.com””
^^^This part needs to be done before anything GIT happens on your PC, as if your workstation doesn’t know who you are in terms of commit users, it will throw an error telling you to configure this setting.
If you clone a remote repo, it will automatically add this remote repo link to the local one, but if you init your own new repo you need to link it manually as described.
With GIT Push / Pull, the syntax will be “git push/pull (url) (branch)” however with clone, you simple need to grab the URL from the remote repo and enter “git clone (url)” with no branch name needed as it will hand you down the most recent copy of its Master branch.
I’m tapping out on the Push / Pull / Etc, time to move on to GIT Branches!
I used the following commands if you cannot read the screenshot:
- “git branch CoolNewFeature” – Created new branch
- “git branch” – Shows all branches in repo
- “checkout branch CoolNewFeature” – Switches from Master to new Branch
- “git log” – Shows initially the Head is on both branches
- “touch / git add / git commit” – Made update to new Branch
- “git log” – Now shows the Head is not on the Master Branch
This is what is known as “Headless Mode” which I didn’t really understand when I first studied it, but now I have a much better understanding of how branching works.
Now that I have said that, lets switch back to the Master branch, and see if my foot inserts into my mouth for being so cocky about my GIT skills:
After a merge “git log” shows that the origin/master is getting left behind, so my next step is to look at “git status” to see how things are looking there:
It quite literally tells us in “git status” to push the branch to sync it up, and so we do, and all is now well… until I begin breaking the very fabric of GIT Timelines and Space:
I first added text to the “NewFeature.txt” file on the secondary branch, commit, then did a different change on the main branch before then merging them together – The problem can be demonstrated perfect in that top graphic at the top of the page:
The “Head” or last commit of the main / master branch was one commit ahead of the secondary branch when the merge was done, so it was exactly like the bottom graphic.
To fix this, the change on the main branch needs to be removed manually by delete the added lines, staged / commit, and then the merge should work here I hope:
There are actually two ways to fix this issue, highlighted are the lines GIT added:
- I could remove the line I created on the main branch file to break the merge
- I could remove all the different GIT messages pointing out the error (which are all highlighted) and keep both the lines I added and do a stage / commit
I’ve done option 1 before, I am going to try option 2 this time:
Hmmm, the odd thing is it seems like its all fine, but we are lagging CoolNewFeature branch some time behind the main, and I am not entirely sure why.
So I decided for now the most prudent action is to admit utter defeat as I am only making the commit timeline worse / longer, and just did a “git log –oneline” and found a commit # before I created the merge conflict, then I reset it to that locally – However I pushed that broken mess up to my GitHub Repo so it is not taking my current Push as my timeline is behind.
Yikes. I will save this post for now and wrap back around to it, I tried to using git diff on the branches / file / in general and that produced nothing so I am going to have to review what I had done incorrectly there 🙂
NOTE – I have been meaning to get around to following up on this post, but will publish this portion of it now, and continue my battle with Merge Conflicts in another post!
You win this battle GIT, but the War is far from over – Will be following up on this!
Although I’d much rather clean this up and post a good solid explanation, I think these notes will be helpful in review of what did not work, so I know what not to try next time 🙂