Git Magic. Chapter 5. Lessons of History

Author: Ben Lynn. Link to original: http://www-cs-students.stanford.edu/~blynn/gitmagic/ch05.html (English).
Tags: git, gitmagic Submitted by mifistor 04.07.2009. Public material.
An alternative online book about Git with the source online.

Know English?

Why don't you want to start to translate this material? You can invite your friends to help you.

* :
 

All can see and participate is translation


Text

== Lessons of History ==

A consequence of Git's distributed nature 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 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.

Some developers strongly feel history should be immutable, warts and all.

Others feel trees should be made presentable before they are unleashed in

public. Git accommodates both viewpoints. Like cloning, branching and merging,

rewriting history is simply another power Git gives you. It is up to you

to use it wisely.

=== I Stand Corrected ===

Did you just commit, but wish you had typed a different message? Then run:

$ git commit --amend

to change the last message. Realized you forgot to add a file? Run *git add* to

add it, and then run the above command.

Want to include a few more edits in that last commit? Then make those edits and run:

$ git commit --amend -a

=== ... And Then Some ===

Let's suppose the previous problem is ten times worse. After a lengthy session you've made a bunch of commits. But you're not quite happy with the way they're organized, and some of those commit messages could use rewording. Then type:

$ git rebase -i HEAD~10

and the last 10 commits will appear in your favourite $EDITOR. A sample excerpt:

pick 5c6eb73 Added repo.or.cz link

pick a311a64 Reordered analogies in "Work How You Want"

pick 100834f Added push target to Makefile

Then:

- Remove commits by deleting lines.

- Reorder commits by reordering lines.

- Replace "pick" with "edit" to mark a commit for amending.

- Replace "pick" with "squash" to merge a commit with the previous one.

If you marked a commit for editing, then run:

$ git commit --amend

Otherwise, run:

$ git rebase --continue

So commit early and commit often: you can easily tidy up later with rebase.

=== Local Changes Last ===

You're working on an active project. You make some local commits over time, and

then you sync with the official tree with a merge. This cycle repeats itself a few times before you're ready to push to the central tree.

But now the history in your local Git clone is a messy jumble of your changes and the official changes. You'd prefer to see all your changes in one contiguous section, and after all the official changes.

This is a job for *git rebase* as described above. In many cases you can use

the *--onto* flag and avoid interaction.

Also see *git help rebase* for detailed examples of this amazing command. You can split commits. You can even rearrange branches of a tree.

=== Rewriting History ===

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.

Afterwards, the +.git/refs/original+ directory describes the state of affairs before the operation. Check the filter-branch command did what you wanted, then delete this directory if you wish to run more filter-branch commands.

Lastly, replace clones of your project with your revised version if you want to interact with them later.

=== Making History ===

[[makinghistory]]

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, 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`:

----------------------------------

commit refs/heads/master

committer Alice <alice@example.com> Thu, 01 Jan 1970 00:00:00 +0000

data <<EOT

Initial commit.

EOT

M 100644 inline hello.c

data <<EOT

#include <stdio.h>

int main() {

printf("Hello, world!\n");

return 0;

}

EOT

commit refs/heads/master

committer Bob <bob@example.com> Tue, 14 Mar 2000 01:59:26 -0800

data <<EOT

Replace printf() with write().

EOT

M 100644 inline hello.c

data <<EOT

#include <unistd.h>

int main() {

write(1, "Hello, world!\n", 14);

return 0;

}

EOT

----------------------------------

Then create a Git repository from this temporary file by typing:

$ mkdir project; cd project; git init

$ git fast-import < /tmp/history

You can checkout the latest version of the project with:

$ git checkout master .

The *git fast-export* command converts any git repository to the

Pages: ← previous Ctrl next
1 2

License: GNU General Public License version 3