git learning note - 8/26/2024
think about it before git commit
git pull
Purpose: Fetch changes from a remote repository and merge them into your current branch.
When you run git pull, it is effectively a combination of two commands:
git fetch: Downloads the latest changes from the remote repository to your local repository but does not merge them. git merge: Merges the fetched changes into your current branch. Default behavior: If there are new commits in the remote branch that are not in your local branch, git pull will merge those commits into your current branch.
git status:
Remote:
A---B---C---D (origin/main)
Local:
A---B---E---F (local branch)
git pull
Remote:
A---B---C---D (origin/main)
Local:
A---B---E---F---M (local branch)
\ /
C---D
- M is a new merge commit created by the merge operation.
- The merge commit (M) combines changes from your local commits (E, F) and the remote commits (C, D).
- The history is now non-linear and includes a merge commit.
git rebase
git rebase is typically used in specific scenarios to rewrite commit history, either to keep a branch up to date with the latest changes from another branch or to clean up your commit history before merging.
Purpose 1: Integrating Changes from Another Branch:
Scenario: You’re working on a feature branch, and you want to incorporate the latest changes from the main branch. Solution: Use git rebase to move your commits on top of the latest main branch commits, effectively integrating the changes without creating a merge commit.
When you run git rebase, you are essentially “moving” your commits to start after the most recent commit on the target branch. This creates a linear history, which is often cleaner and easier to understand.
main branch:
A---B---C---D (main)
feature-branch:
\
E---F---G (feature-branch)
When you run git rebase main on feature-branch, you want to move the feature-branch so that it appears as if it was developed on top of the latest commit on main (commit D), instead of branching off from B.
git checkout feature-branch
git rebase main
A---B---C---D (main)
\
E'---F'---G' (feature-branch)
Key Points:
- The rebase does not change the commits on main (A, B, C, D remain untouched).
- The feature-branch commits are “rebased” onto D, creating a new history for feature-branch.
- After the rebase, your feature-branch appears as if it was created from the latest commit on main (D).
This process makes the history cleaner and linear, avoiding unnecessary merge commits that could clutter the commit history.
Purpose2:Cleaning Up Your Commit History(related to squashing) Squashing commits is a powerful technique for cleaning up your commit history and making your Git logs more readable. It’s typically done using interactive rebase (git rebase -i) and is most often used before merging a feature branch into the main branch to ensure that the history is clean and concise.
Scenario: You have multiple small, related commits in your branch that you want to combine into a single commit before merging into main. Solution: Use interactive rebase (git rebase -i) to squash commits together, reorder commits, or edit commit messages.
git rebase -i HEAD~3 # Squash the last 3 commits into one
Important Notes:
- Squashing is a destructive operation: The original commits are removed, and a new commit is created. This means that the commit history is rewritten, which can be problematic if the commits have already been pushed to a shared repository.
- Push with force: After squashing, if you’ve already pushed the original commits to a remote repository, you’ll need to use git push —force (or git push —force-with-lease) to update the remote branch.
git pull —rebase
It is a best practice in many workflows where a clean commit history is desired. It combines the benefits of keeping your branch up-to-date with the remote branch while avoiding the clutter of merge commits,especially in shared repositories where multiple developers are working on the same codebase.
git pull --rebase origin main
# This command fetches the latest changes from the main branch of the origin remote and rebases your current branch on top of those changes, effectively updating your branch with the latest code while maintaining a linear history.
The most common use case for git pull —rebase is when you are working on a feature branch, and you want to incorporate the latest changes from the main branch without creating unnecessary merge commits.
git pull —rebase vs git pull
git status:
Remote:
A---B---C---D (origin/main)
Local:
A---B---E---F (local branch)
git pull --rebase
Remote:
A---B---C---D (origin/main)
Local:
A---B---C---D---E'---F' (local branch)
When you run git pull —rebase, Git fetches the changes from the remote, and then instead of merging, it rebases your local commits on top of the fetched commits. This avoids creating a merge commit and results in a linear history.
git pull
# Merges remote changes into your branch, potentially creating a new merge commit and resulting in a non-linear history.
A---B---E---F---M (local branch)
\ /
C---D
git pull --rebase
# Rebases your local commits on top of the remote changes, creating a linear history without merge commits.
A---B---C---D---E'---F' (local branch)
git merge —squash
Before the squash merge:
A---B---C---D (main)
\
E---F---G (feature-branch)
Performing the Squash Merge:
git checkout main
git merge --squash feature-branch
git commit -m "Merged feature-branch with squash"
A---B---C---D---H (main)
\
E---F---G (feature-branch)
-
Commit H is a single commit but not a merge commit on main that represents all the changes from commits E, F, and G on feature-branch.
-
The original commits E, F, and G still exist in feature-branch, but they are not added to main’s history.
Use Cases for git merge —squash:
-
Clean and Linear History: You want to keep the history of your main branch clean and concise, without including every commit from a feature branch.It does not record the feature branch as a parent in the commit history.
-
Single Logical Change: The changes in the feature branch represent a single logical change that you want to encapsulate in one commit.