The Friday Evening Frustration: An Ode to Git Commands

ยท

9 min read

Picture this: It's Friday evening, and you've been working hard all week to complete a task assigned to you by your team. You're feeling accomplished and ready to wrap up for the weekend, but there's one final step left - pushing your work to the team's Git repository.

However, as you try to execute the final git command, you realize you're working on the wrong branch and you're met with unexpected roadblocks that threaten to derail your weekend plans.

If you've been in this situation before, you're not alone. Git is notorious for being one of those tasks that can be super annoying and frustrating, especially when you're just about to clock out for the weekend.

In this article, we'll explore some scenarios where you have to switch your commits/changes to a different branch, so you can enjoy your weekend without the dark cloud on the horizon of unresolved git conflicts ๐Ÿ™ˆ

Scenario 1: Switch your unpushed commits to a different branch (git reset --soft)

One common scenario that can make evenings frustrating is when you realize that you've been working on the wrong branch ๐Ÿคฆโ€โ™‚๏ธ

Perhaps you started making changes on a feature branch, only to later realize that you should have been working on a different branch, such as a bugfix branch or a release branch.

In such cases, you may need to switch all your commits to the correct branch.

Let's say you're currently on a feature branch called feature/branch1 and you've made some commits that you want to transfer to another branch called feature/branch2.

First, create a backup branch to safeguard your changes in case anything goes wrong. You can do this by running the following command:

git checkout -b feature/backup-branch

Next, switch back to the original branch feature/branch1 using the following command:

git checkout feature/branch1

Now, use git log to identify the commit(s) that you want to transfer to feature/branch2. Make a note of the commit hash(es). Let's say your log looks like this:

#the work added by you, that's not yet in sync with the live repo 
commit sha-3
commit sha-2
#the last commit from the live repo 
commit sha-1

Run git reset --soft followed by the commit hash of the last commit before your changes. For example:

 # for our earlier example:
git reset โ€“-soft sha-1
#OR
git reset --soft HEAD~2 #undo last 2 commits but keep the changes unstaged

If HEAD is pointed at sha-3 when we start, and then perform a git reset โ€“soft sha-1, HEAD will move to that commit.

All of the changes that were committed in sha-2 and sha-3 are preserved and re-added to the index as staged changes.

Now, switch to the target branch feature/branch2 using the following command:

git checkout feature/branch2

Finally, commit the changes to feature/branch2 using the following command:

git add .
git commit -m "New commit"

This will create a new commit on feature/branch2 with the changes that you transferred from feature/branch1

Please note that git reset --soft is a powerful command that should be used with caution, as it can potentially overwrite or delete commits permanently. It's always a good practice to create a backup branch before making any changes to ensure you can easily recover from any mistakes.

Scenario 2: Duplicate all my commits in a new commit on a different branch (git cherry-pick)

This scenario is somehow similar to the previous one, except this time you already pushed your commits to the remote repo. It also applies to other scenarios as well where you simply want to duplicate some commits from one branch to another.

To do this, checkout to the branch where you want to apply changes:

git checkout starting-point-branch

And there you have 2 options that we'll only impact the history but in essence are doing the same:

  1. Either you duplicate your commits:
# it will bring all commit changes but also stage them
git cherry-pick <commit-hash>
  1. Either you bring only the changes from your commits and submit your work as a new commit:
# it will bring all commit changes but leave them unstaged
git cherry-pick -n <commit-hash> #OR
git cherry-pick --no-commit <commit-hash>

So for this step, the actual flow will look like this:

git checkout starting-point-branch
git cherry-pick -n <commit-1-hash>
git cherry-pick -n <commit-2-hash>
git cherry-pick -n <commit-3-hash>
git cherry-pick -n <commit-4-hash>
git commit -m 'new commit with changes from 4 previous commits'
git push

Note: When you cherry-pick commits, git attempts to apply the changes from those commits to your current branch. However, if the changes in the cherry-picked commits conflict with the changes in your current branch, you'll be faced with resolving those conflicts before you can complete the cherry-pick.

Another important note: git cherry-pick relies on commit hashes to identify the specific commits you want to apply, and if you're not careful, you may cherry-pick unintended changes or accidentally skip important commits, leading to confusion and potential mistakes in your codebase.

Scenario 3: Undo a git merge/commit (git reset --hard / git revert)

How do you undo a Git merge/commit before push?

If you need to undo a Git merge or commit before pushing your changes to a remote repository, you can use the following commands:

To reset to the last undamaged commit:

git reset --hard <last-undamaged-commit-sha>

If you only need to reset to the state of the remote branch:

git reset --hard origin/<name-of-branch>

This command will forcefully perform a "git pull" to overwrite local files, allowing you to perform a clean reset of your branch.

How do you undo a Git merge after pushing the changes?

If you have already pushed the merge commit to the remote repository, you will need to create a new commit that reverts the changes. You can use the following command:

git revert -m 1 <merge-commit-sha>

This will create a new commit that undoes the changes made by the merge commit, effectively reverting the changes back to the state before the merge ๐Ÿ’ช๐ŸคŸ

Scenario 4: Update commits to remote (git commit --amend [--no-edit] / git push --force)

Update commits unpushed to remote

If you haven't pushed the merge commit to the remote repository yet and you notice a mistake in the commit message or forgot to include updates to certain files, you can use the git commit --amend command to update the last commit.

To update the commit message:

git commit --amend -m "new commit message"

Or, if you need to add changes to files that were omitted:

git add .
git commit --amend --no-edit

The --no-edit flag will retain the same commit message, allowing you to include the missing changes to the previous commit. This can be useful to keep your commit history clean and organized, especially when the changes are related to the same work.

Update commits already pushed to remote

Please note that updating commits that have already been pushed to the remote repository should be done with caution, as it can potentially overwrite remote commits that may not be on your local machine. Proceed with caution and make sure to communicate with your team before making such changes.

If you need to update commits that have already been pushed to the remote repository, you can use the following commands:

To force-push local changes and overwrite the remote repository:

git push origin/remote-branch --force

Alternatively, you can use the git revert command to undo a specific commit with a new commit:

git revert <sha of commit>

This will create a new commit that undoes the changes made by the unwanted commit. This approach will keep a record of the changes in the commit history, but the state of the code will be restored to the previous state before the unwanted commit. Again, exercise caution when using these commands to avoid unintentional loss of remote commits. Communication with your team is crucial in such scenarios.

Scenario 5: Save your work without commit (git stash)

If you find yourself in a situation where you've made some changes but aren't ready to commit yet or you need to switch to another branch, you can use git stash to save your work temporarily.

To save your changes in a stash, you can simply run:

git stash // saves your work

This will create a new stash with a default name, such as stash@{0}, and store your changes without committing them. You can then switch to another branch or perform other tasks without worrying about committing incomplete changes.

When you want to resume your work, go back to the desired branch and:

git stash pop // continue from where you left off

If you use git stash frequently and want to add a label to your stash for easier identification, you can use the following command:

git stash save name-your-tmp-changes

This allows you to provide a custom name for your stash, making it easier to locate in your list of stashes.

To view your list of stashes, you can use the command:

git stash list

Each stash will be displayed with its name and index.

To retrieve the changes from a specific stash, you can use git stash apply followed by the index of the stash. For example:

git stash apply <index-of-stash> // e.g., git stash apply 2

Alternatively, you can use git stash pop followed by the index of the stash, which not only retrieves the changes but also removes the stash from the list of stashes.

It's worth noting that git stash pop and git stash apply behave differently in terms of stash history. When you use git stash apply, the most recently saved stash will overwrite files in the current working tree but leave the stash history unchanged. On the other hand, the pop command restores files but then deletes the applied stash.

In addition to the basic stash commands, there are some other useful options available:

  • git stash clear: This command empties the stash list by removing all the stashes.

  • git stash drop <stash_id>: This command deletes a specific stash from the stash list.

  • git stash branch <new_branch_name stash_id>: This command creates a new branch based on the commit the stash was created from and applies the stashed changes to it, effectively creating a new branch with the changes from the stash.

Using git stash can be a handy way to save your work temporarily without committing incomplete changes, allowing you to switch branches or perform other tasks with ease. However, it's important to note that stashes are not meant to be a permanent solution and should be used as a temporary measure. Make sure to properly commit your changes once they are complete and thoroughly tested.

Conclusion

In the end, mastering Git commands like git cherry-pick, git reset, git revert, git commit --amend, and git stash can save your Friday evening from turning into a coding nightmare.

These commands offer powerful ways to selectively apply, undo, modify, and temporarily store changes in your codebase.

Whether you need to pick specific commits, undo commits or move changes, revert changes, amend commits, or save changes without committing, git has you covered.

Just remember to use them wisely, review and test your changes thoroughly, and communicate with your team to avoid potential conflicts.

With these tools, you can confidently manage your code changes and enjoy your well-deserved weekend.

ย