• Aucun résultat trouvé

Forms of the git diff Command

Dans le document Version Control with Git (Page 124-128)

If you pick two different root-level tree objects for comparison, git diff yields all deviations between the two project states. That’s powerful. You could use such a diff to convert wholesale from one project state to another. For example, if you and a coworker are developing code for the same project, a root-level diff could effectively sync the repositories at any time.

There are three basic sources for tree or tree-like objects to use with git diff:

• Any tree object anywhere within the entire commit graph

• Your working directory

• The index

Typically, the trees compared in a git diff command are named via commits, branch names, or tags, but any commit name we discussed earlier in “Identifying Com-mits” on page 65 suffices. Also, both the file and directory hierarchy of your working directory, and the complete hierarchy of files staged in the index, can be treated as trees.

The git diff command can perform four fundamental comparisons using various combinations of those three sources:

git diff

git diff shows the difference between your working directory and the index. It exposes what is dirty in your working directory and is thus a candidate to stage for your next commit. This command does not reveal differences between what’s in your index and what is permanently stored in the repository (not to mention remote repositories you might be working with).

git diff commit

This form summarizes the differences between your working directory and the given commit. Common variants of this command name HEAD or a particular branch name as the commit.

git diff --cached commit

This command shows the differences between the staged changes in the index and the given commit. A common commit for the comparison—and the default if no commit is specified—is HEAD. With HEAD, this command shows you how your next commit will alter the current branch.

If the option --cached doesn’t make sense to you, perhaps the synonym --staged will. It is available in Git version 1.6.1 and later.

git diff commit1 commit2

If you specify two arbitrary commits, the command displays the differences be-tween the two. This command ignores the index and working directory, and it is the workhorse for arbitrary comparisons between two trees that are already in your object store.

The number of parameters on the command line determines what fundamental form is used and what is compared. You can compare any two commits or trees. What’s being compared need not have a direct or even an indirect parent-child relationship. If you don’t supply a tree object or two, git diff compares implied sources, such as your index or working directory.

Let’s examine how these different forms apply to Git’s object model. The example in Figure 8-1 shows a project directory with two files. The file file1 has been modified in the working directory, changing its content from “foo” to “quux.” That change has been staged in the index using git add file1, but it is not yet committed.

A version of the file file1 from each of your working directory, the index, and the HEAD have been identified. Even though the version of file1 that is “in the index,”

bd71363, is actually stored as a blob object in the object store, it is indirectly referenced

Forms of the git diff Command | 107

through the virtual tree object that is the index. Similarly, the HEAD version of the file, a23bf, is also indirectly referenced through several steps.

This example nominally demonstrates the changes within file1. The bold arrows in the figure point to the tree or virtual tree objects to remind you that the comparison is actually based on complete trees and not just on individual files.

From Figure 8-1, you can now see how using git diff without arguments is a good technique for verifying the readiness of your next commit. As long as that command emits output, you have edits or changes in your working directory that are not yet staged. Check the edits on each file. If you are satisfied with your work, use git add to stage the file. Once you stage a changed file, the next git diff no longer yields diff output for that file. In this way, you can step progressively through each dirty file in

Working directory

git diff

git diff HEAD

git diff --cached Index

Object store

master HEAD

a23bf

foo bar

file1 file2

9d3a2 bd71363

file1 quux

quux bar

file2 project

This is the working directory version

This is the version

“in the index”

This is the HEAD version

Figure 8-1. Various file versions that can be compared

your working directory until the differences disappear, meaning that all files are staged in your index. Don’t forget to check for new or deleted files, too. At any time during the staging process, the command git diff --cached shows the complementary changes, or those changes already staged in the index that will be present in your next commit. When you’re finished, git commit captures all changes in your working di-rectory into a new commit.

You are not required to stage all the changes from your working directory for a single commit. In fact, if you find you have conceptually different changes in your working directory that should be made in different commits, you can stage one set at a time, leaving the other edits in your working directory. A commit captures only your staged changes. Repeat the process, staging the next set of files appropriate for a subsequent commit.

The astute reader might have noticed that, although there are four fundamental forms of the git diff command, only three are highlighted with bold arrows in Figure 8-1.

So, what is the fourth? There is only one tree object represented by your working di-rectory, and there is only one tree object represented by the index. In the example, there is one commit in the object store along with its tree. However, the object store is likely to have many commits named by different branches and tags, all of which have trees that can be compared with git diff. Thus, the fourth form of git diff simply compares any two arbitrary commits (trees) already stored within the object store.

In addition to the four basic forms of git diff, there are myriad options as well. Here are a few of the more useful ones:

--M

The --M option detects renames and generates a simplified output that simply re-cords the file rename rather than the complete removal and subsequent addition of the source file. If the rename is not a pure rename but also has some additional content changes, Git calls those out.

-w or --ignore-all-space

Both -w and --ignore-all-space compare lines without considering changes in whitespace as significant.

--stat

The --stat option adds statistics about the difference between any two tree states.

It reports in a compact syntax how many lines changed, how many were added, and how many were elided.

--color

The --color option colorizes the output; a unique color represents each of the different types of changes present in the diff.

Finally, the git diff may be limited to show diffs for a specific set of files or directories.

Forms of the git diff Command | 109

The -a option for git diff does nothing even remotely like the -a option for git commit. To get both staged and unstaged changes, you use git diff HEAD. The lack of symmetry is not only unfortunate but counterintuitive.

Dans le document Version Control with Git (Page 124-128)