Paul's Tutorials - logoGit Operations Reference


Programming Home

This page is intended to provide extra information about some of git's features, as well as expose and document others. While they are not explicitly necessary to know when using git, they can be helpful when using git or trying to accomplish effective version control.

Unlike the Tips and Tricks pages from the other tutorials, this page only requires that you have read and understood the concepts in chapter 1.

Tagging

There may come a time during the life of your repository that you find that you have reached a specific milestone, such as a version release, a specific deadline, or perhaps a stable feature set. At this point, you may want to leave some sort of marker on the history so you can come back to it if need be. Granted, you could just revert back to the commit hash at this point, but wouldn't it be difficult to have to remember even just the first 7 characters of the commit hash forever?

Luckily, git has a feature for just this situation, called a tag. When you make a tag, you can effectively label a specific commit with an arbitrary name, such as v1.0, or v0.2.3-alpha. This allows you to quickly grab the code from that point in history wiithout having to remember the commit hash.

In a sense, tagging is a little like branching. You create another reference in the repository, which points to a specific commit, however, tags do not have history. You cannot develop on a tag the way you can on a branch.

Creating a New Tag

To create a new tag from the current HEAD on the commandline, you can just do the following:

git tag -a <tag-name>

where tag-name is what you wish to name the tag. Or, if you want to make a tag from a specific branch or commit, you can do this like you would when you make a branch:

git tag -a <tag-name> <source>

With regards to naming, a tag's name should be a version number (with an optional v prefix), and follow a sensible versioning system.

When you execute this command, it will bring up a text editor for you to leave a message. This is a good place to leave some release notes about your software at this particular point in development.

Unlike commit messages, tag messages don't have a title — only a body.

When you're done, save the file. This will save the tag message, and git will add the tag to its list of references.

In a GUI, where this function is found can vary. In EGit, it is located under Advanced in the Team menu. In TortoiseGit, this function is called Create Tag and is located in the primary TortoiseGit menu.

Deleting Tags

Although you really shouldn't find yourself in a situation where you need to delete a tag, this is possible as well, using the -d switch of the git tag command:

git tag -d <tag-name>

Pushing Tags

If you want to push a tag to the remote repository, the git push command looks a little different.

git push --tags origin

This command will push all of the tags to origin. Because tags generally don't change, this really just pushes new tags to the remote.

If you use a GUI, the normal push process should work.

What if I want to develop from the codebase on a tag?

No problem. Just use the tag as a source for a new branch.

git branch myCode v1.0
git checkout -b myCode v1.0

Alternatively, if you need to reset a branch to the state of the tag, and the tag's commit is in that branch's history, then you can use the tag with your reset command:

git reset --hard v1.0

Manually Patching the Tree

Even though merging is a wonderful thing, it will always merge everything from the two branches' most recent common ancestor to their present HEADs. This is sufficient in most cases, but sometimes you may find yourself needing to merge just a few specific commits from one branch into another.

Because of the nature of merging, this is not really possible by doing a really complex merge. You have to do some of the heavy lifting yourself.

The process for this, however, is simple. The first step is to get a diff across all of the commits you want and save it to a file:

git diff <first-commit> <last-commit> > mydiff.patch

This command will generate an overarching commit for every commit made from first-commit to last-commit and store it in a text file called mydiff.patch.

The next step from here is to take the patch and apply it to the proper branch (while being sure to keep track of mydiff.patch). So, switch to the branch you want to apply the patch to, and then use the git apply command to apply the diff to the working tree.

git apply mydiff.patch

Important Notes about git apply

Firstly, git apply works without looking at your repository's history. All it does is look at the patch file you give it and apply the changes that the patch file specifies. Because of this, code conflicts will not occur. This may seem like a blessing at first, but it actually means that running git apply is like running git merge with the --theirs switch. Any changes listed in the patch will always take precedence over changes that you have made in your local directory.

Secondly, git apply is limited because it doesn't access the commit history — if a file has changed enough so that git can't really tell what lines are supposed to go where, you may end up with some interesting results.

Finally, and partly as a function of the last point, newlines and whitespaces can screw up the patch application process often. If this is the case, git will ask you to run the apply command with the --ignore-whitespace or --whitespace=nowarn options.