Everybody know the basic Git commands like checkout, clone, add, commit or push, but there are more commands and more options that people do not usually use in their daily work.
One of these "advanced" options is --amend and it is used for correcting a commit. Sometimes you want to commit your changes because you do not want to loose your changes, but your project does not build because it has some errors (or some tests fail). When the --amend option you can commit again and fix the last commit. If you want to try that commit again, you can run commit with the --amend option. You can edit the last commit message the same as always, but it overwrites your previous commit.
$ git commit -m 'initial commit'
$ git add forgotten_file
$ git commit --amend
In Git, people usually integrate changes from one branch into another using merge, but there are some scenarios where you want to have a clean and linear history. In that case, the best way to go it is using rebase.
Suppose you have the next scenario and run the next commands.
$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command
The result you will get it is the next
and if finally you run the next commands then you will get the final scenario.
$ git checkout master
$ git merge experiment
As you can see, there is no difference with merging, but rebasing makes for a cleaner history (the log of a rebased branch looks like a linear history and appears that all the work happened in series). Finally, there is only one rule you have to follow: do not rebase commits that exist outside your repository.
Also, maybe you did not notice, but the previous examples uses an automatic rebase. What if you want to do an interactive rebase? Well, you can use the -i option.
$ git rebase -i master
It opens the text editor and shows you the list of commits you have done.
pick 33d5b7a Message for commit #1
pick 9480b3d Message for commit #2
pick 5c67e61 Message for commit #3
Suppose that the second commit it is a fix over the first commit and you do not want to show it in the log history. You can do it using the fixup option.
pick 33d5b7a Message for commit #1
fixup 9480b3d Message for commit #2
pick 5c67e61 Message for commit #3
As summary, merge takes all the changes in one branch and merges them into another branch in one commit. Rebase says I want the point at which I branched to move to a new starting point.
Let us say you have created a branch for the purpose of developing a single feature. When you want to bring those changes back to master, you probably want merge (you don't care about maintaining all of the interim commits).
A second scenario would be if you started doing some development and then another developer made an unrelated change. You probably want to pull and then rebase to base your changes from the current version from the repo.
OK, let us see what we can do if we want to change the last three commit messages, or any of the commit messages in that group, you supply as an argument to git rebase -i the parent of the last commit you want to edit:
$ git rebase -i HEAD~3
Running this command gives you a list of commits in your text editor that looks something like this:
pick 33d5b7a Message for commit #1
pick 9480b3d Message for commit #2
pick 5c67e61 Message for commit #3
Now, you can edit the commits using the word edit:
edit 5c67e61 Message for commit #3
pick 33d5b7a Message for commit #1
pick 9480b3d Message for commit #2
Finally, in order to do it persistent, you have to run the next commands:
$ git commit --amend
$ git rebase --continue
Of course, you can remove any of these commits deleting the line related with the commit you want to remove.
Sometimes, you would like to take a series of commits and squash them down into a single commit because they do not have any meaning separately.
If you specify squash, Git applies both that change and the change directly before it and makes you merge the commit messages together.
pick 33d5b7a Message for commit #1
squash 9480b3d Message for commit #2
squash 5c67e61 Message for commit #3
It will make a single commit from these three commits. Of course you can modify the messages in the commits.
As you know it is not very difficult to switch a single Git repository between multiple branches or to create a second local clone of a repository (people usually use this approach). However, maintaining multiple clones of a repository means extra work to keep the clones in sync with each other and with any remote repositories.
The new Git subcommand worktree creates additional working trees connected to an existing Git repository. Each linked working tree is a pseudo-repository with its own checked-out working copy.
Suppose you are working in a Git repository on a branch called feature, when a user reports a high-urgency bug in master. First you create a linked working tree with a new branch hotfix checked out relative to master and switch to that directory:
$ git worktree add -b hotfix ../hotfix origin/master
Enter ../hotfix (identifier hotfix)
Branch hotfix set up to track remote branch master from origin.
Switched to a new branch 'hotfix'
Now you have got a new working tree with branch hotfix checked out and ready to go. You can fix the bug, push hotfix and create a pull request. After you have committed the changes to the hotfix branch, you can delete the hotfix directory whenever you like, because the commits are stored in your main repository:
$ cd ../main
$ rm -rf ../hotfix
Miguel Angel Alvarez
Tags: git tools commands options
September 15th 2016