Git Version Control
🚀 What is Git?
Git is a version control cli utility that helps programmers work together on the same set of code. Most git commands happen locally and other third parties such as GitHub and GitLab are git hosting providors that provide a way to store code and changes on the cloud. So, lets dive in and see how to use git to keep a clean, logical repository.
🛠️ Getting Started
Our git repositories are located on github at: https://github.com/orgs/Project-Jump/repositories. Its easy to clone these files into your local workspace by just doing
- git clone <link-to-repo>
🚼 Making a change
We now have the code we want to modify locally. Lets say we want to make some changes. Here we introduce the concept of branches. You can think of a branch as a set of commits. The default branch in GitHub is main. Because we want to participate in a code review, we want to create a new branch that we can use to merge into main. In this example lets say we are adding a feature that adds push notifications. To create a branch and checkout to it do:
- git branch feature/issue-13/push-notifications
- git checkout feature/issue-13/push-notifications
In this case we follow the naming conventions here: https://dev.to/varbsan/a-simplified-convention-for-naming-branches-and-commits-in-git-il4. Now we can make any changes we need to, in order to add the push notification feature.
🚢 Deploy out our change
To deploy out our change onto GitHub, we first add a commit to our local branch. Here run a git status and git add any relavent files that have been marked as modified. This stages our changes and marks them to be committed when we next run git commit -m "feat: add push notification functionality". Here's quick read on writing effective git commit messages: https://skerritt.blog/writing-better-commit-messages/#how-to-title-a-git-commit-message.
To make sure our commit is in our branch run git log and verify. Now we are ready to run git push to push our branch to GitHub and automatically generate a link to create a pull request. You may get an error when trying to push an outdated branch saying the tip of your branch is out of date, in this case you can run git push --force if you believe there will be no merge conflicts.
👏🏼 Squashing commits
It's helpful to have just one commit be associated with your branch, this way the repo has a clean and easy to follow commit history with one commit per issue. If you have more than one commit we need to squash them. To do that run git log to determine how many commits need to be squashed and then run git rebase -i HEAD~<number of commits to squash>. This will open a vim terminal listing out all the commits. Just replace pick with s on every commit other than the first one to squash them. After saving and quitting with vim by entering :wq you will be brought to a screen with all the commit messages you are trying to squash; combine these into one cohesive commit message and then save and quit again using :wq. You should now be left with a single squashed commit when checking git log.
⏪ My PR is behind main
In many circumstances, you may have an open PR that needs to be updated with the changes in main due to merge conflicts. To do this go to the branch of the PR and make a temp branch off of it with your changes. Then copy the commit id of the PR commit. The commit id is a shortened version of the commit hash visible when using git log. While you are still in the branch associated with the PR, run git reset --hard HEAD~1 to undo the PR commit. Then run git rebase origin/main to get all the new commits in main onto your branch. Finally run git cherry-pick <commit-id> with the PR commit id you copied to cherry pick the PR changes onto the branch. This puts your changes on top of the new origin/main changes. If there are merge conflicts resolve them as described below.
🔀 Resolving merge conflicts
A merge conflict means that your local changes and the incoming changes from GitHub are attempting to edit the same file in different ways. For each merge issue you can either accept the incoming change, accept your local change, or accept both changes. Manually go to each conflicting file (you can see what files are conflicting) and resolve each merge issue accordingly. Once all merge conflicts have been resolved, you can run git cherry-pick --continue or git merge --continue depending on where the conflict originated from to complete the merge.
❗ Common mistakes
- I made my changes directly off the main branch
- In this case commit and squash your changes as normal into one commit and then branch off of main. Your commit will follow you. Then you can continue to work or push the new branch. You can then go back to the main and run
git reset --hard HEAD~1to reset main to be inline with the currentorigin/mainin GitHub.
📝 Git commands review
I highly recommend you to use git as it was meant to be used, a cli utility. This way you have full control of what git is doing to your local and remote workspace. Lets go over some basic git commands that you will be using often and what they do.
- git clone <repo-link>: Copys a remote repository to your local computer
- git status: Gives important information about your current workspace including file staging status and current branch info
- git log: Shows a list of previous commits made
- git add/restore/rm <filepath>: Stages/unstages/removes a file to be committed respectively.
- git commit -m "<commit-message>": Commits a set of staged changes locally
- git cherry-pick <commit-id>: Puts a commit in a different branch on top of your current changes
- git reset --hard <past-commit>: Moves local branch back to a past commit
- git rebase -i <past-commit>: An interactive way to squash commits
- git rebase <Another branch>: Adds all commits from given branch to the current branch.
- git push: Pushes current branch changes to GitHub.