diff options
Diffstat (limited to 'third_party/git/Documentation/howto/keep-canonical-history-correct.txt')
-rw-r--r-- | third_party/git/Documentation/howto/keep-canonical-history-correct.txt | 216 |
1 files changed, 0 insertions, 216 deletions
diff --git a/third_party/git/Documentation/howto/keep-canonical-history-correct.txt b/third_party/git/Documentation/howto/keep-canonical-history-correct.txt deleted file mode 100644 index 35d48ef714..0000000000 --- a/third_party/git/Documentation/howto/keep-canonical-history-correct.txt +++ /dev/null @@ -1,216 +0,0 @@ -From: Junio C Hamano <gitster@pobox.com> -Date: Wed, 07 May 2014 13:15:39 -0700 -Subject: Beginner question on "Pull is mostly evil" -Abstract: This how-to explains a method for keeping a - project's history correct when using git pull. -Content-type: text/asciidoc - -Keep authoritative canonical history correct with git pull -========================================================== - -Sometimes a new project integrator will end up with project history -that appears to be "backwards" from what other project developers -expect. This howto presents a suggested integration workflow for -maintaining a central repository. - -Suppose that that central repository has this history: - ------------- - ---o---o---A ------------- - -which ends at commit `A` (time flows from left to right and each node -in the graph is a commit, lines between them indicating parent-child -relationship). - -Then you clone it and work on your own commits, which leads you to -have this history in *your* repository: - ------------- - ---o---o---A---B---C ------------- - -Imagine your coworker did the same and built on top of `A` in *his* -repository in the meantime, and then pushed it to the -central repository: - ------------- - ---o---o---A---X---Y---Z ------------- - -Now, if you `git push` at this point, because your history that leads -to `C` lacks `X`, `Y` and `Z`, it will fail. You need to somehow make -the tip of your history a descendant of `Z`. - -One suggested way to solve the problem is "fetch and then merge", aka -`git pull`. When you fetch, your repository will have a history like -this: - ------------- - ---o---o---A---B---C - \ - X---Y---Z ------------- - -Once you run merge after that, while still on *your* branch, i.e. `C`, -you will create a merge `M` and make the history look like this: - ------------- - ---o---o---A---B---C---M - \ / - X---Y---Z ------------- - -`M` is a descendant of `Z`, so you can push to update the central -repository. Such a merge `M` does not lose any commit in both -histories, so in that sense it may not be wrong, but when people want -to talk about "the authoritative canonical history that is shared -among the project participants", i.e. "the trunk", they often view -it as "commits you see by following the first-parent chain", and use -this command to view it: - ------------- - $ git log --first-parent ------------- - -For all other people who observed the central repository after your -coworker pushed `Z` but before you pushed `M`, the commit on the trunk -used to be `o-o-A-X-Y-Z`. But because you made `M` while you were on -`C`, `M`'s first parent is `C`, so by pushing `M` to advance the -central repository, you made `X-Y-Z` a side branch, not on the trunk. - -You would rather want to have a history of this shape: - ------------- - ---o---o---A---X---Y---Z---M' - \ / - B-----------C ------------- - -so that in the first-parent chain, it is clear that the project first -did `X` and then `Y` and then `Z` and merged a change that consists of -two commits `B` and `C` that achieves a single goal. You may have -worked on fixing the bug #12345 with these two patches, and the merge -`M'` with swapped parents can say in its log message "Merge -fix-bug-12345". Having a way to tell `git pull` to create a merge -but record the parents in reverse order may be a way to do so. - -Note that I said "achieves a single goal" above, because this is -important. "Swapping the merge order" only covers a special case -where the project does not care too much about having unrelated -things done on a single merge but cares a lot about first-parent -chain. - -There are multiple schools of thought about the "trunk" management. - - 1. Some projects want to keep a completely linear history without any - merges. Obviously, swapping the merge order would not match their - taste. You would need to flatten your history on top of the - updated upstream to result in a history of this shape instead: -+ ------------- - ---o---o---A---X---Y---Z---B---C ------------- -+ -with `git pull --rebase` or something. - - 2. Some projects tolerate merges in their history, but do not worry - too much about the first-parent order, and allow fast-forward - merges. To them, swapping the merge order does not hurt, but - it is unnecessary. - - 3. Some projects want each commit on the "trunk" to do one single - thing. The output of `git log --first-parent` in such a project - would show either a merge of a side branch that completes a single - theme, or a single commit that completes a single theme by itself. - If your two commits `B` and `C` (or they may even be two groups of - commits) were solving two independent issues, then the merge `M'` - we made in the earlier example by swapping the merge order is - still not up to the project standard. It merges two unrelated - efforts `B` and `C` at the same time. - -For projects in the last category (Git itself is one of them), -individual developers would want to prepare a history more like -this: - ------------- - C0--C1--C2 topic-c - / - ---o---o---A master - \ - B0--B1--B2 topic-b ------------- - -That is, keeping separate topics on separate branches, perhaps like -so: - ------------- - $ git clone $URL work && cd work - $ git checkout -b topic-b master - $ ... work to create B0, B1 and B2 to complete one theme - $ git checkout -b topic-c master - $ ... same for the theme of topic-c ------------- - -And then - ------------- - $ git checkout master - $ git pull --ff-only ------------- - -would grab `X`, `Y` and `Z` from the upstream and advance your master -branch: - ------------- - C0--C1--C2 topic-c - / - ---o---o---A---X---Y---Z master - \ - B0--B1--B2 topic-b ------------- - -And then you would merge these two branches separately: - ------------- - $ git merge topic-b - $ git merge topic-c ------------- - -to result in - ------------- - C0--C1---------C2 - / \ - ---o---o---A---X---Y---Z---M---N - \ / - B0--B1-----B2 ------------- - -and push it back to the central repository. - -It is very much possible that while you are merging topic-b and -topic-c, somebody again advanced the history in the central repository -to put `W` on top of `Z`, and make your `git push` fail. - -In such a case, you would rewind to discard `M` and `N`, update the -tip of your 'master' again and redo the two merges: - ------------- - $ git reset --hard origin/master - $ git pull --ff-only - $ git merge topic-b - $ git merge topic-c ------------- - -The procedure will result in a history that looks like this: - ------------- - C0--C1--------------C2 - / \ - ---o---o---A---X---Y---Z---W---M'--N' - \ / - B0--B1---------B2 ------------- - -See also http://git-blame.blogspot.com/2013/09/fun-with-first-parent-history.html |