GIT: Some Advanced Usage
Interactive rebase
You may probably want to change commits on the branch, you are currently woring on. For example, you want to change commit message, or split some commits:
Here we want to change last four commiths (HEAD~3
). After this command opens an editor with the rebase script. But before
we continue, behind the scenes git will move our four commits to a temporary directory. Then it runs all commands from the
rebase script. So let’s no have a look at the rebase script:
Notince, that commits in the rebase script are shown from the first commit to the latest one. For example, in git log
command
the commits are shown from the oldest to the newest. After saving the rebase script, commits from the temporary foled
will be applied in the order we have specified.
Split commits
If we want to split a commit into two commits, we can use interactive rebase.
edit
command. At first, put theedit
command for the required commit in the rebase script. Then, when we save and exit the rebase script, git will run all the commits, and stops at theedit
command waiting for the prompt.- Undo last changes in the working directory:
git reset HEAD^
. So our files become unstaged: - Add the files to the stage:
git add
- Commit the files:
git commit -m
- Repeat with the other files.
- Continue to rebase with
git rebase --continue
.
Clear history
Let’s imagine that you have committed a large dump for your tests in a repository. Then you have done some
changes in it and also have committed them. So our repository has become too large. How to change it? First of
all, before any movements make a backup: git clone our-repo
.
To change a history call: git filter-branch --tree-filter <shell command>
. It will check out each commit from the
working directory, run the specified <shell command>
and then recommit the files:
In the command above -- --all
means filter all commits in all branches.
If our repo is too large, we can use --index-filter
and git will run our shell command on each commit only on staged files.
Notice, that if the specified command will fail the filter will stop.
Before running filter-branch
for the second time, we must use -f
flag, to force the command. Because git has created
a backup of the repo and force
will override it. After clearing history some commits may become empty. We can clear our
repo from them with
Restore Data
Commits
In our repo we have some sort of commits history:
And we want to move back to bug fix: git reset --hard 56wcf1q
. But some moments later, we have understood
that it was a mistake. How do we restore a feature_#2 commit?. Of course, now there is no feature_#2 commit in our log:
But git never removes commits and it has a special reflog, which is available only in your local repo. If we type this command:
it will show a removed commit. This command shows a list of HEAD commits: where the HEAD has been pointing at each change.
Our removed commit is now like an orphan, it isn’t attached to any branch. To move it back we can use git reset --hard 59e5b5f
.
Or we can use a shortcut git reset --hard HEAD@{1}
instead of a hash. Now our commit has come back:
Branches
Some day we go and delete a branch:
And then we remember, that we haven’t merged it into our master branch. So, it’s time to restore it. As we remember git never
deletes commits. It has removed a branch but commits still exist. Now we must find the latest commit from the removed branch and
create a new branch, that will point to this commit. As in the previous example, we can use git reflog
command to find the
needed commit. And then we just create a new branch, that points to this commit:
Cherry picking
When do you need cherry picking? It may be useful when we want some piece of the functionality to be moved to our branch from another one. And this code exists in one commit. So, in other words, we want to move a commit from one branch to another.
Here are our steps:
- Checkout the branch where we need to put a commit:
git checkout master
- Use this command with the hash of the required commit:
git cherry-pick q19dqe3
- Optionally you can change a commit message:
git cherry-pick --edit q19dqe3
. This will open an editor for changing a commit message.
Notice, that not the hash of the commit in the master
branch has been changed. That happens because these commits have
different parents.
It is possible to cherry pick several commits into one: git cherry-pick --no-commit q19dq3 fs41t92
.
This command takes specified commits and applies them to the current HEAD. But it doesn’t make any commits on the current
branch. Then we need to commit applied changes into their own commit.