Pulling In Temporary Changes To Your Branch
If you have some small improvements on branch
A that make debugging/testing easier that are not yet reviewed/pushed to master, and you are working on branch
B, you can bring these useful changes into
B without polluting the branch with:
If you don’t want to bring in all the changes from branch
A to branch
B, you can instead
cherry-pick specific commits:
The above command will just bring over the changes from the latest commit on
A, not the entire history of the branch. The
git reset removes the changes from your index. You can of course replace
A with a specific commit hash.
Amending To The Last Commit
--amend is a useful way to add more changes to the last commit. When using
--amend, git will add staged changes to the last commit, rather than creating a new one. It will also let you modify the commit message (unless you pass the
If you don’t want to modify the commit message, pass the
If you are pushing a branch with an amended commit, you may have to use the
-f (force) flag if the remote already has a copy of the commit you modified.
When force pushing, make sure you are pushing to the right branch, as this command can overwrite/delete history!
Using git commit –fixup
--fixup option to
git commit allows you to add commits which can be automatically squashed into a commit of your choice when rebasing.
The following command will add an staged changes to a special
--fixup, you do not specify a commit message. The commit message is created for you, and will start with
!fixup, followed by a space and then the message of the commit the fixup points to.
--fixupwill also modifies the git history (once you rebase). You should
fixupcommits on private (local) branches, and never on public branches. Fixing up commits that have been shared with other developers will cause history conflicts which are difficult to resolve.
--fixup behaves slightly different to
--amend, one of the main differences is that you can rewrite any commit in the current history, not just the last one as you can with
--fixup is a great tool for keeping your git history clean when making small bug fixes and improvements to already committed features on a development branch. This is best shown with an example:
rebase command above,
8f82c^ was used to say “I want to rebase off the commit BEFORE
8f82c. Note all these hashes are shortened versions of the full hash, which will as long as there are no hash collisions (with 5 characters, it’s unlikely there will be for a small number of commits).
You can permanently change your
git settings so that you don’t have to add
--autosquash every time you do a rebase:
The default log message size can be quite verbose. To condense each log message to a single line and only show the last 10 log messages:
To include information on what files where changed in each commit, add the
git reflog, although sounding much like
git log, behaves very differently. The
reflog is actually a very special branch that records the position of
HEAD (i.e. auto-commits every time
HEAD changes) for the last 30 days (by default). It is a local branch that is not shared with remotes, so cloning will not preserve a
git reflogas the undo history of your repo.
The purpose of
git reflog is to provide a fail-safe incase you do a
git operation that would otherwise wipe your data.
git reflog allows you to:
- Recover from commits made on a detached
- Fix a non-bare
If I run
git reflog on this blog’s repository, I see something similar to:
Set vim As The Default Editor For Git
Run the following command to set
vim as the default text editor for
vim should load whenever git wants to present you with an editor, e.g. when calling
git commit without the
git bisect is a useful tool to hunt down the exact commit which caused a regression in a test. It can do a manual or automatic binary search through all the commits from a known good to known bad commit, finding the first commit in where the test/build went from passing to failing.
You can start a bisection with:
BAD_COMMIT is the hash of a commit which is known to be bad (fails the tests), and
GOOD_COMMIT is the hash of a commit which is known to be good (passes the tests). The next step depends on whether you want to do it somewhat manually by providing user input at each iteration, or completely automatically.
Automatic git bisect
git bisect can be completely automated by providing a command to
git bisect run.
$ git bisect run <command>
You can exit the git
bisect state with
git bisect reset:
You can view the current status of the bisection at any time with the command:
You can automate the entire process by provided
git bisect with a script to run on every iteration. You have the freedom to do anything you want in this script (e.g. run specific tests) as long as you return
0 if this commit is o.k., or a
1 if the commit is bad (fails.)
Suppose you want to add some custom changes to every run. You can
cherry-pick some changes before running the test command:
DO NOT leave the repo status in a state other than what git bisect had configured it in.
Bisecting, a merge base must be tested.
To give you an indication on the number of commits involved in the bisection, you can manually print out a tidy list of all the commits between
Force With Lease
“Force pushing” with git is common when you are working on a branch and using
git commit --amend and
git rebase to keep your commit history clean and rebase of master. However,
git push -f can have disastrous consequences if someone else has pushed changes to the branch that you don’t have in your local copy.
To mitigate this, you can use the
This will only force push as long as there are no new changes on the branch since last time you pulled or fetched from the remote. This will prevent you from accidentally wiping someone’s pushed changes on the branch. However, there is one major caveat,
git push --force-with-lease will not protect you from overwriting changes if you fetch from the origin and do not integrate the changes into your version of the branch. This is because git checks your local
ref for the remote branch and only lets you force push if it is the same as the remote
ref. If you run
git fetch (instead of
git pull), this will update your local
ref without incorporating the changes into your version of the branch.
--force-with-lease is a finger-full to type. To make things easier, you can create an alias like so:
To use, now just type
git pushf at the command-line.
Get A Diff Of All The Changes On Your Branch
Once you have worked on your branch for a while, you may find that you want to get a
diff of all the changes you have made. You may think that the following would work:
The problem with the above command is that if other changes have made their way onto
master since you branched of it, these will also be displayed in the diff along with the changes you have made on your branch. What you really want to do is display the diff between the
HEAD of your branch and
master at the point you branch of it. This is called the
merge-base. You can find the
merge-base commit hash with:
However, git has special syntax which allows you to perform a comparison with the
merge-base in a much simpler way using the triple dot
If you are currently on your branch, this can be simplified even further to:
This work is licensed under a Creative Commons Attribution 4.0 International License .
- Git Submodules
- Managing Large Repos
- Git Quickstart Guide
- Git Ignore For Visual Studio
- Converting Mercurial Repos To Git
- version control systems