Max Zavati

Practical Git and Gitflow Snippets

Feb 22, 2025
Practical Git and Gitflow Snippets

This article will serve as a snippet of commands and steps with explanations that I use in my day-to-day job when working with Git and GitHub. It will also include common errors and instructions on how to connect to GitHub using a generated access token.

Common Commands

Initialize a Git Repository

git init

Initializes a new Git repository in the current directory.

Clone an Existing Repository

git clone <repo-url>

Clones a remote repository to your local machine.

Checking the Status of the Repository

git status

Displays the current state of your working directory and staging area.

Add a Remote Origin

To add a remote origin for your repository, run this command:

git remote add origin <remote-repository-URL>

Replace <remote-repository-URL> with the URL of your remote repository (e.g., https://github.com/username/repository.git).

Check the Remote Origin

To verify that the remote origin has been successfully added, run:

git remote -v

This will display the remote repository URLs associated with your local repository. You'll see something like:

origin  https://github.com/username/repository.git (fetch)
origin  https://github.com/username/repository.git (push)

Set a New Remote Origin

If you want to set a new remote origin (replace the existing one), you can use:

git remote set-url origin <new-remote-repository-URL>

Replace with the new repository URL.

Creating a New Branch

git checkout -b <new-branch>

Creates and switches to a new branch.

View Commit History

git log

Shows the commit history.

Stage Files for Commit

git add <file>       # Stage a specific file
git add .            # Stage all changes

Adds changes to the staging area, preparing them for commit.

Commit Changes

git commit -m "message"

Commits the staged changes with a descriptive message.

Checkout a Specific Commit or Branch

git checkout <branch-name>   # Switch to a branch
git checkout <commit-hash>   # Checkout a specific commit (detached HEAD)

Switches to a branch or a specific commit.

Merge Branches

git merge <branch-name>

Merges the specified branch into the current branch. This might trigger conflicts if changes are incompatible.

Resolving Merge Conflicts

When a conflict arises, Git will mark the conflicting files. Open the files and resolve conflicts manually. After fixing conflicts:

git add <file>  # Stage resolved files
git commit      # Commit the merge

Resolves and finalizes the merge by committing.

View Differences (Diff)

git diff               # Show changes in unstaged files
git diff --staged      # Show changes in staged files

Displays the differences between your working directory and the staging area or last commit.

Undo Changes in Working Directory (Discard Unstaged Changes)

git checkout -- <file>  # Undo changes to a specific file

Discards local changes in a file (unstaged).

Stashing Changes (Save Changes Temporarily)

git stash

Temporarily saves changes in a stash so you can work on something else.

To apply the stashed changes:

git stash apply

Pop Stash (Apply and Remove the Stash)

git stash pop

Applies the most recent stash and removes it from the stash list.

Push Changes to Remote

git push origin <branch-name>

Pushes your local branch to the remote repository.

Pull Changes from Remote

git pull origin <branch-name>

Fetches and merges changes from the remote repository to your local branch.

Delete a Local Branch (If Not Checked Out)

git branch -d <branch-name>

Deletes the local branch, but only if it has been fully merged with the current branch (prevents data loss).

Force Delete a Local Branch (If Not Merged)

git branch -D <branch-name>

Forces the deletion of the local branch, even if it hasn’t been merged. Be careful, as this can result in losing unmerged changes.

Reset to a Specific Commit (Not Deleting Changes)

git reset <commit-hash>

Resets the HEAD to a specific commit but does not remove any changes from the working directory (this is the default "mixed" reset).

Remove the Last Commit (Soft Reset)

git reset --soft HEAD~1

Moves HEAD to the previous commit but keeps the changes staged. You can modify and recommit them.

Remove the Last Commit (Hard Reset)

git reset --hard HEAD~1

Moves HEAD to the previous commit and discards all changes (both staged and unstaged) in the working directory.

Amend the Last Commit

git commit --amend

Modify the last commit, either by editing the commit message or adding changes.

Cherry-Pick a Commit

git cherry-pick <commit-hash>

Applies the changes from a specific commit onto your current branch.

Force-Push Changes

git push --force

Pushes changes to the remote repository, even if it requires overwriting history. Be careful with this as it rewrites history.

Remove a Commit from History (Interactive Rebase)

git rebase -i HEAD~n  # Where n is the number of commits to go back

Opens an editor where you can choose to drop or modify commits in your history. To permanently remove commits and rewrite history:

git push --force

Tagging a Commit

git tag <tag-name> <commit-hash>

View Stash List

git stash list

Shows a list of stashed changes.

Removing a Remote Branch

git push origin --delete <branch-name>

Deletes a remote branch.

Undo Changes in a File and Discard Staged Changes

git reset <file>         # Unstage a file (but keep changes)
git checkout -- <file>   # Discard changes from the working directory

Unstages a file or discards changes in the working directory.

Basic Rebase

git checkout <feature-branch>      # Switch to the branch you want to rebase
git rebase <target-branch>          # Rebase onto the target branch (e.g., `main` or `develop`)

This command will reapply the commits from feature-branch onto the tip of main. If there are no conflicts, it will result in a linear history. Git rebase applies your changes on top of another branch's commits, essentially re-writing history to make it look like your changes were made after the other branch’s changes. This eliminates the merge commits that would appear when using git merge, giving you a cleaner, linear commit history. So, while both git merge and git rebase integrate changes, rebase does so without introducing extra merge commits, making the history look more streamlined.

Delete a Commit during an Interactive Rebase

  1. Start the rebase:
git rebase -i HEAD~n

Replace n with the number of commits you want to go back. 2. Mark the commit for deletion:

  • In the editor that opens, locate the commit you want to delete.
  • Change pick to drop for the commit you want to remove.
  • Save and close the editor.
  1. Resolve any conflicts (if they arise during the rebase):
  • Git will stop and notify you of conflicts.
  • Fix the conflicts in the affected files.
  • After resolving conflicts, stage the changes with:
git add <file>
  • Continue the rebase
git rebase --continue
  1. Push the changes (force push is required since history has been rewritten):
git push origin <branch-name> --force

That’s it! We deleted a commit, resolved any conflicts, and pushed the changes.

Git Flow Workflow

GitFlow is a branching model for Git, created by Vincent Driessen at nvie, that defines a set of best practices for managing and releasing software projects. It provides a structured way to use Git, particularly for teams, ensuring consistent workflows and easy collaboration.

Example

A complete example demonstrating a Feature Branch Flow is as follows. Assuming we have a repo setup with a main branch.

git checkout main
git checkout -b develop
git checkout -b feature_branch
# work happens on feature branch
git checkout develop
git merge feature_branch
git checkout main
git merge develop
git branch -d feature_branch

In addition to the feature and release flow, a hotfix example is as follows:

git checkout main
git checkout -b hotfix_branch
# work is done commits are added to the hotfix_branch
git checkout develop
git merge hotfix_branch
git checkout main
git merge hotfix_branch

The overall flow of Gitflow is:

  1. A develop branch is created from main
  2. A release branch is created from develop
  3. Feature branches are created from develop
  4. When a feature is complete it is merged into the develop branch
  5. When the release branch is done it is merged into develop and main
  6. If an issue in main is detected a hotfix branch is created from main
  7. Once the hotfix is complete it is merged to both develop and main

How to Use a GitHub Token to Connect to a Remote Repository

To generate a GitHub token, go to: Settings Developer settings Personal access tokens.

Here’s an example with placeholders for your GitHub token, username, and repository:

git remote set-url origin https://<YOUR_GITHUB_TOKEN>@github.com/<YOUR_GITHUB_USERNAME>/<YOUR_REPO_NAME>.git

Replace the following placeholders: <YOUR_GITHUB_TOKEN> with your actual GitHub token. <YOUR_GITHUB_USERNAME> with your GitHub username. <YOUR_REPO_NAME> with the name of your repository. Make sure to keep your GitHub token secure and avoid sharing it publicly.

Some Errors and Fixes

Resolving Divergent Branches

When you see the error "You have divergent branches and need to specify how to reconcile them", follow these steps:

  1. Fetch the latest changes:
git fetch origin
  1. Rebase your branch on top of the latest updates from develop:
git rebase origin/develop

This will apply your changes on top of the latest develop branch updates.

  1. Push your changes:
git push origin develop

Resolving Conflicts (If Any)

If conflicts arise during the rebase:

  1. Fix the conflicts in the affected files.
  2. Stage the resolved files:
git add .
  1. Continue the rebase:
git rebase --continue

Share on:

Contact Me

Have an opportunity, wanna collaborate on something cool or just say hello!

Send Email