You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: book/07-git-tools/sections/replace.asc
+25-25Lines changed: 25 additions & 25 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,15 +1,15 @@
1
1
[[_replace]]
2
-
=== Replace
2
+
=== 替换
3
3
4
-
Git's objects are unchangable, but it does provide an interesting way to pretend to replace objects in it's database with other objects.
4
+
Git 对象是不可改变的,但它提供一种有趣的方式来用其他对象假装替换数据库中的 Git 对象。
5
5
6
-
The `replace` command lets you specify an object in Git and say "every time you see this, pretend it's this other thing". This is most commonly useful for replacing one commit in your history with another one.
For example, let's say you have a huge code history and want to split your repository into one short history for new developers and one much longer and larger history for people interested in data mining. You can graft one history onto the other by `replace`ing the earliest commit in the new line with the latest commit on the older one. This is nice because it means that you don't actually have to rewrite every commit in the new history, as you would normally have to do to join them together (because the parentage effects the SHAs).
Let's try this out. Let's take an existing repository, split it into two repositories, one recent and one historical, and then we'll see how we can recombine them without modifying the recent repositories SHA values via `replace`.
We'll use a simple repository with five simple commits:
12
+
我们将使用一个拥有 5 个提交的简单仓库:
13
13
14
14
[source,console]
15
15
----
@@ -21,11 +21,11 @@ c6e1e95 fourth commit
21
21
c1822cf first commit
22
22
----
23
23
24
-
We want to break this up into two lines of history. One line goes from commit one to commit four - that will be the historical one. The second line will just be commits four and five - that will be the recent history.
Well, creating the historical history is easy, we can just put a branch in the history and then push that branch to the master branch of a new remote repository.
OK, so our history is published. Now the harder part is truncating our recent history down so it's smaller. We need an overlap so we can replace a commit in one with an equivalent commit in the other, so we're going to truncate this to just commits four and five (so commit four overlaps).
It's useful in this case to create a base commit that has instructions on how to expand the history, so other developers know what to do if they hit the first commit in the truncated history and need more. So, what we're going to do is create an initial commit object as our base point with instructions, then rebase the remaining commits (four and five) on top of it.
To do that, we need to choose a point to split at, which for us is the third commit, which is `9c68fdc` in SHA-speak. So, our base commit will be based off of that tree. We can create our base commit using the `commit-tree` command, which just takes a tree and will give us a brand new, parentless commit object SHA back.
@@ -80,12 +80,12 @@ $ echo 'get history from blah blah blah' | git commit-tree 9c68fdc^{tree}
80
80
81
81
[NOTE]
82
82
=====
83
-
The `commit-tree` command is one of a set of commands that are commonly referred to as 'plumbing' commands. These are commands that are not generally meant to be used directly, but instead are used by **other** Git commands to do smaller jobs. On occasions when we're doing weirder things like this, they allow us to do really low-level things but are not meant for daily use. You can read more about plumbing commands in <<_plumbing_porcelain>>
OK, so now that we have a base commit, we can rebase the rest of our history on top of that with `git rebase --onto`. The `--onto` argument will be the SHA we just got back from `commit-tree` and the rebase point will be the third commit (the parent of the first commit we want to keep, `9c68fdc`):
88
+
现在我们已经有一个基础提交了,我们可以通过 `git rebase --onto` 命令来将剩余的历史变基到基础提交之上。`--onto` 参数是刚才 `commit-tree` 命令返回的 SHA 值,变基点会成为第三个提交(我们想留下的第一个提交的父提交,`9c68fdc`):
89
89
90
90
[source,console]
91
91
----
@@ -97,10 +97,10 @@ Applying: fifth commit
97
97
98
98
image::images/replace4.png[]
99
99
100
-
OK, so now we've re-written our recent history on top of a throw away base commit that now has instructions in it on how to reconstitute the entire history if we wanted to. We can push that new history to a new project and now when people clone that repository, they will only see the most recent two commits and then a base commit with instructions.
To combine them, you can simply call `git replace` with the commit you want to replace and then the commit you want to replace it with. So we want to replace the "fourth" commit in the master branch with the "fourth" commit in the `project-history/master` branch:
Now, if you look at the history of the `master` branch, it appears to look like this:
144
+
现在,查看 `master` 分支中的历史信息,显示如下:
145
145
146
146
[source,console]
147
147
----
@@ -153,11 +153,11 @@ e146b5f fifth commit
153
153
c1822cf first commit
154
154
----
155
155
156
-
Cool, right? Without having to change all the SHAs upstream, we were able to replace one commit in our history with an entirely different commit and all the normal tools (`bisect`, `blame`, etc) will work how we would expect them to.
Interestingly, it still shows `81a708d` as the SHA, even though it's actually using the `c6e1e95` commit data that we replaced it with. Even if you run a command like `cat-file`, it will show you the replaced data:
This means that it's easy to share our replacement with others, because we can push this to our server and other people can easily download it. This is not that helpful in the history grafting scenario we've gone over here (since everyone would be downloading both histories anyhow, so why separate them?) but it can be useful in other circumstances.
0 commit comments