Skip to content

Commit

Permalink
Moved Personal Experience section to chapter on history.
Browse files Browse the repository at this point in the history
  • Loading branch information
blynn committed Nov 9, 2008
1 parent f366552 commit a3dcb00
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 41 deletions.
19 changes: 2 additions & 17 deletions branch.txt
Expand Up @@ -168,25 +168,10 @@ You can have multiple stashes, and manipulate them in various ways. See

=== Work How You Want ===

Applications such as http://www.mozilla.com/[Mozilla Firefox] allow you to open multiple tabs and multiple windows. Switching tabs gives you different content in the same window. Git branching is like tabs for your working directory. Continuing this analogy, Git cloning is like opening a new window. Being able to do both easily makes for a better user experience.
Applications such as http://www.mozilla.com/[Mozilla Firefox] allow you to open multiple tabs and multiple windows. Switching tabs gives you different content in the same window. Git branching is like tabs for your working directory. Continuing this analogy, Git cloning is like opening a new window. Being able to do both easily improves the user experience.

On a higher level, several Linux window managers allow you to have multiple desktops: you can instantly switch to a different desktop. This is similar to branching in Git, whereas Git cloning would be like attaching another monitor to gain another desktop.

Yet another example is the http://www.gnu.org/software/screen/[*screen*] utility. This gem allows you to create, destroy and switch between multiple terminal sessions in the same terminal. Instead of opening new terminals (clone), you can use the same one if you run *screen* (branch). In fact, you can do a lot more with *screen* but that's a topic for another text.

Cloning, branching, and merging are fast and local in Git, encouraging you to use the combination that best suits you. Git allows you to work exactly how you want.

==== Personal Experience ====

The equivalent of branching and cloning in centralized version control systems, when it exists, requires network communication. This precludes working offline, and means these systems need more expensive network infrastructure, especially as the number of users grows.

Most importantly, these operations will be slower to some degree, usually to the point where users won't bother using them unless absolutely necessary. And when they absolutely have to run slow commands, productivity suffers because of an interrupted work flow.

I experienced these phenomena first-hand. Git was the first version control system I used, and I grew accustomed to it, taking many features for granted. I did not know what centralized systems were like, and assumed they were similar. Later, I was forced to use one.

Often I have a flaky internet connection. This matters little with Git, but
makes development unbearable with a centralized system. Additionally, I found
myself conditioned to avoid certain commands because of the latencies involved,
which ultimately prevented me from following the work flow I wanted.

When I had to run a slow command, the interruption to my train of thought dealt a disproportionate amount of damage. While waiting for server communcation to complete, I'd do something else to pass the time, such as check email or write documentation. By the time I returned to the original task, the command had already finished long ago. I would then spend a long time trying to remember what I was doing.
Cloning, branching, and merging are fast and local in Git, encouraging you to use the combination that best suits you. Git lets you work exactly how you want.
4 changes: 2 additions & 2 deletions clone.txt
Expand Up @@ -109,6 +109,6 @@ Then go to the new directory and run:

The procedure for giving your changes to everyone else depends on the other version control system. The new directory contains the files with your changes. Run whatever commands of the other version control system are needed to upload them to the central repository.

Tip: The *git svn* command automates the above for Subversion repositories.
You can also run it to
The *git svn* command automates the above for Subversion repositories, and can
also be used to
http://google-opensource.blogspot.com/2008/05/export-git-project-to-google-code.html[export a Git project to a Subversion repository].
25 changes: 19 additions & 6 deletions grandmaster.txt
Expand Up @@ -86,7 +86,7 @@ The HEAD tag is like a cursor that normally points at the latest commit, advanci

will move the HEAD three commits backwards in time. Thus all Git commands now act as if you hadn't made those last three commits, while your files remain in the present. See the git reset man page for some applications.

But how can you go back to the future? The past commits do not know anything of the future.
But how can you go back to the future? The past commits know nothing of the future.

If you have the SHA1 of the original HEAD then:

Expand All @@ -98,11 +98,12 @@ But suppose you never took it down? Don't worry, for commands like these, Git sa

=== HEAD-hunting ===

Perhaps ORIG_HEAD isn't enough. Perhaps you've just realized you made a monumental mistake last month and you need to go back to an ancient commit in a long-forgotten branch.
Perhaps ORIG_HEAD isn't enough. Perhaps you've just realized you made a monumental mistake and you need to go back to an ancient commit in a long-forgotten branch.

It's hard to lose Git commits permanently, even after deleting branches. As long as you never run *git gc \--prune*, your commits are preserved forever and can be restored at any time.

The trouble is finding the appropriate hash. You could look at all the hash values in `.git/objects` and use trial and error to find the one you want. But there's a much easier way.
By default, Git keeps a commit for at least two weeks, even if you ordered
Git to destroy the branch containing it. The trouble is finding the appropriate
hash. You could look at all the hash values in `.git/objects` and use trial
and error to find the one you want. But there's a much easier way.

Git records every hash of a commit it computes in `.git/logs`. The subdirectory `refs` contains the history of all activity on all branches, while the file `HEAD` shows every hash value it has ever taken. The latter can be used to find hashes of commits on branches that have been accidentally lopped off.

Expand All @@ -112,7 +113,19 @@ The reflog command provides a friendly interface to these log files. Try

and see its manpage for more information.

Eventually, you may want to run *git gc \--prune* to recover space. Be aware that doing so prevents you from recovering lost HEADs.
You may wish to configure a longer grace period for doomed commits. For
example:

$ git config gc.pruneexpire "30 days"

means a deleted commit will only be permanently lost once 30 days have passed
and *git gc* is run.

You may also wish to disable automatic invocations of *git gc*:

$ git conifg gc.auto 0

in which case commits will only be deleted when you run *git gc* manually.

=== Building On Git ===

Expand Down
74 changes: 59 additions & 15 deletions history.txt
@@ -1,11 +1,10 @@
== Lessons of History ==

A consequence of the distributed nature of Git is that history can be edited
easily. But if you tamper with the past, take care:
only rewrite that part of history which you alone possess. Just as nations
forever argue on who committed what atrocity, if someone else has a clone whose
version of history differs to yours, you will have trouble reconciling when
your trees interact.
easily. But if you tamper with the past, take care: only rewrite that part of
history which you alone possess. Just as nations forever argue over who
committed what atrocity, if someone else has a clone whose version of history
differs to yours, you will have trouble reconciling when your trees interact.

Of course, if you control all the other trees too, then there is no problem
since you can overwrite them.
Expand Down Expand Up @@ -72,26 +71,30 @@ Also see *git help rebase* for detailed examples of this amazing command. You ca

=== Rewriting History ===

Occasionally, there are situations that call for the equivalent of the
Stalinesque practice of airbrushing people out of official photos, erasing them
from history. For example, suppose we intend to release a project, but it
involves a file that should be kept private for some reason. Perhaps I left my
credit card number in a text file and accidentally added it to the project.
Deleting the file is insufficient, for the file can be accessed from older
commits. We must remove the file from all commits:
Occasionally, you need the source control equivalent of airbrushing people out
of official photos, erasing them from history in a Stalinesque fashion. For
example, suppose we intend to release a project, but it involves a file that
should be kept private for some reason. Perhaps I left my credit card number in
a text file and accidentally added it to the project. Deleting the file is
insufficient, for the file can be accessed from older commits. We must remove
the file from all commits:

$ git filter-branch --tree-filter 'rm top/secret/file' HEAD

See *git help filter-branch*, which discusses this example and gives a faster
method. In general, *filter-branch* lets you alter large sections of history with a single command.
method. In general, *filter-branch* lets you alter large sections of history
with a single command.

Afterwards, you must replace all clones of your project with your revised version if you wish to interact with them later.
Afterwards, you must replace clones of your project with your revised version if you wish to interact with them later.

=== Making History ===

Want to migrate a project to Git? If it's managed with one of the more well-known systems, then chances are someone has already written a script to export the whole history to Git.

Otherwise, take a look at *git fast-import*. This command takes text input in a specific format and creates Git history from scratch. Typically a script is cobbled together and run once, migrating the project in a single shot.
Otherwise, look up *git fast-import*, which reads text input in a specific
format to create Git history from scratch. Typically a script using this
command is hastily cobbled together and run once, migrating the project in a
single shot.

As an example, paste the following listing into temporary file, such as `/tmp/history`:
----------------------------------
Expand Down Expand Up @@ -138,3 +141,44 @@ Then create a Git repository from this temporary file by typing:
You can checkout the latest version of the project with:

$ git checkout master .

=== Personal Experience ===

In a centralized version control system, history modification is a difficult
operation, and only available to administrators. Cloning, branching, and
merging are impossible without network communication. So are basic operations
such as browsing history, or committing a change. In some systems, users
require network connectivity just to view their own changes or open a file for
editing.

Centralized systems preclude working offline, and need more expensive network
infrastructure, especially as the number of developers grows. Most
importantly, all operations are slower to some degree, usually to the point
where users shun advanced commands unless absolutely necessary. In extreme
cases this is true of even the most basic commands. When users must run slow
commands, productivity suffers because of an interrupted work flow.

I experienced these phenomena first-hand. Git was the first version control
system I used. I quickly grew accustomed to it, taking many features for
granted. I simply assumed other systems were similar: choosing a version
control system ought to be no different from choosing a text editor or web
browser.

I was shocked when later forced to use a centralized system. My often flaky
internet connection matters little with Git, but makes development unbearable
when it needs to be as reliable as local disk. Additionally, I found myself
conditioned to avoid certain commands because of the latencies involved, which
ultimately prevented me from following my desired work flow.

When I had to run a slow command, the interruption to my train of thought
dealt a disproportionate amount of damage. While waiting for server
communcation to complete, I'd do something else to pass the time, such as
check email or write documentation. By the time I returned to the original
task, the command had finished long ago, and I would waste more time trying to
remember what I was doing. Humans are bad at context switching.

There was also an interesting tragedy-of-the-commmons effect: anticipating
network congestion, individuals would consume more bandwidth than necessary on
various operations in an attempt to reduce future delays. The combined efforts
intensified congestion, encouraging individuals to consume even more bandwidth
next time to avoid even longer delays.
2 changes: 1 addition & 1 deletion intro.txt
Expand Up @@ -46,7 +46,7 @@ A small project may only need a fraction of the features offered by such a syste

=== Merge Conflicts ===

For this topic, our computer game analogy becomes too thinly stretched since most games never worry about this. Instead, let us again consider the case of editing a document.
For this topic, our computer game analogy becomes too thinly stretched. Instead, let us again consider editing a document.

Suppose Alice has inserted a line at the beginning of a file, and Bob appends one at the end. They both upload their changes. Most systems will automatically deduce a reasonable course of action: accept and merge their changes, so both Alice's and Bob's edits are applied.

Expand Down

0 comments on commit a3dcb00

Please sign in to comment.