Git Reference
Branches
You can have any branch structure you want. Branches are stored in a directory structure. The files of the repo exist in the folder for a given branch.
In this example, my_fancy_branch
is a branch in a folder called andy
, which is in a folder called experimental
. This structure organizes branches by their purpose. Any branch can be merged into any other branch regardless of this folder structure; it's just a way of organizing branches.
Gerrit has special namespaces for specific purposes. The following is for pushing branches for code review.
Under this, you would put your branch according to whatever folder structure your team uses.
Working with Branches
List all branches:
Create a new branch as a copy of the current branch:
Move to a different branch:
Delete a branch:
Rename a branch:
Get local copy of a remote branch:
Duplicate an existing branch and checkout the new branch copy:
Create a new branch from the current branch starting at a specific commit:
Pushing to Remote Branches
Push from specific local branch to specific remote branch:
Rebasing
Pull latest master and rebase your local master on top of it.
Rebase a new feature branch onto master:
Rebase onto a remote branch:
Pull
Alternate way to pull down a remote branch:
Delete all local UNCOMMITTED changes to a specific file:
Move all committed changes back to staging area (keep them staged and tracked, but not committed):
Unstage files, but keep them tracked:
Unstage and untrack files at once:
Revert all unstaged changes:
Discard all untracked files and changes, including any cherry-picked commits:
This is how you can erase a cherry-pick you added to your branch for testing before the cherry-picked commit gets merged.
Untracked: Unknown to git, never been added with
git add
Unstaged: Known to git, previously added with
git add
, but changed since then and changes not yet staged for next commit
Working with Commits
Interactive Rebase
Useful for:
Squash commits
Edit commit messages
Edit individual commits in a chain of commits
It is important to understand how an interactive rebase works.
The way it works is it goes back in the commit history to where you tell it to start. From that point, it rebuilds each commit in the chain one at a time with the staged changes at each step.
It follows the basic workflow:
Stage Changes -> Commit -> Move to next commit
Edit a Specific Commit in a Chain
To edit a specific commit in a chain without affecting the other commits, do as follows:
Make changes to the commit chosen. When changes are made:
IMPORTANT: If merge conflicts are found:
Resolve them
Run
git rebase --continue
DO NOT git commit --amend
after resolving merge conflicts. Resolving (in VSCode) will automatically stage the conflict fixes. Keep the fixes in the staging area.
Amending the conflict fixes will combine them with the current commit in the rebase process, not the commit that caused the conflict. The effect will be that commits will be squashed and will disappear from the chain.
Simply fix each merge conflict, then run git rebase --continue
.
Comparing changes line-by-line
Visualizing commit tree:
Git Bisect for triaging commits to find the root cause of a test failure:
Split Large Commit into Smaller Commits
Commit with Changes to Existing Files
This method uses git add -p
to selectively stage hunks of each file and commit them separately.
If the large commit contains new files, the above method won't work. When you reset changes from the staging area, instead of going to tracked but unstaged, they will go to fully untracked.
There is no way to get them to be tracked but unstaged, so git never sees them as "changes" and will not let you do git add -p
. It will just say "no changes" when you try.
Commit with New Files
Instead, we create a new branch for our new commit chain. Then we reach over to the branch with the large commit and pull in hunks of changes one at a time.
Select y
to add the hunk, or e
to edit it in place (break it up further).
Instead of using e
, you can also use y
to add the whole thing, then go into the file manually, delete parts you don't want, and git add .
to stage those deletions.
You don't really need to use checkout -p
at all in this case. You can just do all the hunk selection from the text editor directly.
Another alternate method is to try going in the other direction; unstaging hunks of changes that you want to remove from the large commit.
Reflog
This is git's undo history.
Command history will be listed in reverse chronological order.
To go back to a previous state, find the HEAD pointer number corresponding to the desired state. The form will be HEAD@{1}
, HEAD@{2}
, etc. chronologically through the history.
Use git reset to go back to that state.
Example: undo the last git commit --amend
:
Last updated