Chapter 12

Tips and Tricks

We did not want to overload the introductory chapters and limited ourselves to the essential concepts and typical applications. In this chapter, however, you will find a collection of tips and tricks, some of which can be very helpful in certain situations but you or others might never need. Probably it is sufficient if you skim this chapter briefly so you know what is here. You can look up the details if you need them.

Don’t Panic, There Is A Reflog!

Git is like a dog. It can smell your fear.

I smiled when I saw this saying in my twitter timeline. Git is actually somewhat intimidating to beginners. But if Git is really a dog, then it is probably a herding dog trying to protect its (developer) herd.

You should know that Git does not immediately delete objects in the repository. Whenever you change something, Git creates new objects in the repository; the old ones are not deleted. Even garbage collection, for example by using the gc command, only deletes objects with a certain minimum age. The default setting for this is two weeks (configuration option: gc.pruneexpire).

In addition, Git keeps track of all changes in a branch. This so-called reflog resides in the .git/logs directory. With the --walk-reflogs option, the log command can display the local history of a branch.

> git log --walk-reflogs mybranch 

If you can find the commit that contains the “lost” changes, then you can bring back the changes again, for example by using the cherry-pick command, the rebase command or with a simple merge.

Attention! For local clones the reflog is normally active. Bare repositories that you normally puts on servers, however, do not have the reflog by default. You can turn it on using this command:

> git config core.logAllRefUpdates true 

It may be useful to make it a system-wide default setting:

> git config --system core.logAllRefUpdates true 

Ignoring Local Changes Temporarily

Sometimes you change files that are managed by Git and that you do not want to include in versioning. An example: When writing this book, we often commented out chapters so that we can complete the document faster. Naturally, we did not want these changes to be versioned. Another example: To find an error, you generate extra debugging information, which will no longer be needed later.

Entries in .gitignore do not help here, because they only work on files that are not yet managed by Git. You can work around the problem by using selective commits. However, this is a bit tedious because then you have to choose again for each subsequent commit, what changes you do and do not want to accept.

Examining Changes to Text Files

The normal Git diff algorithm compares two files line by line. In your source code, you often change single lines without touching the neighboring lines, which means differences can be easily noticed with diff. In text files, however, it is a different story. Changes are often wrapped, i.e. words move from one line to another. From the output of diff, it is hard to see what exactly has changed in a text file.

> git diff

...
-Walter goes every
-day to schiil.
+Walter goes to
+school.
...

For continuous text, the --word-diff option can help as it can show changes word by word.

> git diff --word-diff 

  ... 
Walter goes [-every -]
[-day] to
[-schiil.-]{+school.+}
  ...

With --word-diff=color you can have the differences highlighted in a different color.

alias - Shortcuts for Git Commands

If you use Git from the command line often, it may be useful to define shortcuts for frequently used commands.

> git config --global alias.ci commit

> git config --global alias.st status

Here we set up aliases ci and st for commit and status, respectively. They can be used immediately. For example:

> git st

Aliases are also considered in Git tab completion (if installed). Therefore, it may also be useful to set up aliases for rarely used commands. For example:

> git config --global alias.ignore-temporarily 
    'update-index --assume-unchanged'

Branches as Temporary Pointers to Commits

If you are looking for errors or trying to fix tricky merge conflicts, you might often remember relevant commits, for example a point where everything was still good, or a merge base. You may start by listing commit hashes on a piece of paper, but you should not do this! You can easily create a branch, once you discover a commit of interest.

> git branch tmp/a-silly-error 8b167

From now on you can refer to the commit by name. The tab completion now “knows” that name. You can, for instance, inquire which tags contain the commit in question.

> git tag --contains tmp/a-silly-error

1.0.2
1.0.3

The following command creates a branch named tmp/merge-base as a pointer to the merge base of the master and feature branches.

> git branch tmp/merge-base 
        'git merge-base master feature'

The tmp/ prefix is a naming convention: This is a namespace for temporary branches, to make it easier to distinguish them from normal branches. It is not a technical requirement. You can call the temporary branches whatever you want.

Later you can clear the branches using the following command.

> git branch -D 
    'git branch --no-color --list tmp/* 
    | grep -v '* ' 
    | xargs'

Moving Commits to Another Branch

When you are making changes, it is of course best to do it on the right branch. But sometimes you make a mistake and do it on the wrong branch. In such a case, you will have to move some commits to another branch.

Figure 12.1: Moving commits from branch A to B

Attention! Moving commits can confuse other developers. You should either move only commits that you have not shared with other developers, or you have to inform the other developers about it and ask them in turn to move commits that were developed on top of the moved commits.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.137.178.9