As you can see, a commit shows who made the latest change, what they
did, and why.
- Every commit has a 40-hexdigit id, sometimes called the "object name"
- or the "SHA1 id", shown on the first line of the "git show" output.
- You can usually refer to a commit by a shorter name, such as a tag or a
- branch name, but this longer name can also be useful. Most
- importantly, it is a globally unique name for this commit: so if you
- tell somebody else the object name (for example in email), then you are
- guaranteed that name will refer to the same commit in their repository
- that it does in yours (assuming their repository has that commit at
- all).
+ Every commit has a 40-hexdigit id, sometimes called the "object name" or the
+ "SHA1 id", shown on the first line of the "git show" output. You can usually
+ refer to a commit by a shorter name, such as a tag or a branch name, but this
+ longer name can also be useful. Most importantly, it is a globally unique
+ name for this commit: so if you tell somebody else the object name (for
+ example in email), then you are guaranteed that name will refer to the same
+ commit in their repository that it does in yours (assuming their repository
+ has that commit at all). Since the object name is computed as a hash over the
+ contents of the commit, you are guaranteed that the commit can never change
+ without its name also changing.
+
+ In fact, in <<git-internals>> we shall see that everything stored in git
+ history, including file data and directory contents, is stored in an object
+ with a name that is a hash of its contents.
Understanding history: commits, parents, and reachability
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
information you need to help resolve the merge.
Files with conflicts are marked specially in the index, so until you
- resolve the problem and update the index, git commit will fail:
+ resolve the problem and update the index, gitlink:git-commit[1] will
+ fail:
-------------------------------------------------
$ git commit
file.txt: needs merge
-------------------------------------------------
- Also, git status will list those files as "unmerged".
+ Also, gitlink:git-status[1] will list those files as "unmerged", and the
+ files with conflicts will have conflict markers added, like this:
+
+ -------------------------------------------------
+ <<<<<<< HEAD:file.txt
+ Hello world
+ =======
+ Goodbye
+ >>>>>>> 77976da35a11db4580b80ae27e8d65caf5208086:file.txt
+ -------------------------------------------------
+
+ All you need to do is edit the files to resolve the conflicts, and then
+
+ -------------------------------------------------
+ $ git add file.txt
+ $ git commit
+ -------------------------------------------------
+
+ Note that the commit message will already be filled in for you with
+ some information about the merge. Normally you can just use this
+ default message unchanged, but you may add additional commentary of
+ your own if desired.
+
+ The above is all you need to know to resolve a simple merge. But git
+ also provides more information to help resolve conflicts:
+
+ Getting conflict-resolution help during a merge
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
All of the changes that git was able to merge automatically are
already added to the index file, so gitlink:git-diff[1] shows only
- the conflicts. Also, it uses a somewhat unusual syntax:
+ the conflicts. It uses an unusual syntax:
-------------------------------------------------
$ git diff
will be HEAD, the tip of the current branch; the other will be the
tip of the other branch, which is stored temporarily in MERGE_HEAD.
- The diff above shows the differences between the working-tree version
- of file.txt and two previous versions: one version from HEAD, and one
- from MERGE_HEAD. So instead of preceding each line by a single "+"
- or "-", it now uses two columns: the first column is used for
- differences between the first parent and the working directory copy,
- and the second for differences between the second parent and the
- working directory copy. Thus after resolving the conflict in the
- obvious way, the diff will look like:
+ During the merge, the index holds three versions of each file. Each of
+ these three "file stages" represents a different version of the file:
+
+ -------------------------------------------------
+ $ git show :1:file.txt # the file in a common ancestor of both branches
+ $ git show :2:file.txt # the version from HEAD, but including any
+ # nonconflicting changes from MERGE_HEAD
+ $ git show :3:file.txt # the version from MERGE_HEAD, but including any
+ # nonconflicting changes from HEAD.
+ -------------------------------------------------
+
+ Since the stage 2 and stage 3 versions have already been updated with
+ nonconflicting changes, the only remaining differences between them are
+ the important ones; thus gitlink:git-diff[1] can use the information in
+ the index to show only those conflicts.
+
+ The diff above shows the differences between the working-tree version of
+ file.txt and the stage 2 and stage 3 versions. So instead of preceding
+ each line by a single "+" or "-", it now uses two columns: the first
+ column is used for differences between the first parent and the working
+ directory copy, and the second for differences between the second parent
+ and the working directory copy. (See the "COMBINED DIFF FORMAT" section
+ of gitlink:git-diff-files[1] for a details of the format.)
+
+ After resolving the conflict in the obvious way (but before updating the
+ index), the diff will look like:
-------------------------------------------------
$ git diff
first parent, deleted "Goodbye" from the second parent, and added
"Goodbye world", which was previously absent from both.
- The gitlink:git-log[1] command also provides special help for merges:
+ Some special diff options allow diffing the working directory against
+ any of these stages:
+
+ -------------------------------------------------
+ $ git diff -1 file.txt # diff against stage 1
+ $ git diff --base file.txt # same as the above
+ $ git diff -2 file.txt # diff against stage 2
+ $ git diff --ours file.txt # same as the above
+ $ git diff -3 file.txt # diff against stage 3
+ $ git diff --theirs file.txt # same as the above.
+ -------------------------------------------------
+
+ The gitlink:git-log[1] and gitk[1] commands also provide special help
+ for merges:
-------------------------------------------------
$ git log --merge
+ $ gitk --merge
-------------------------------------------------
- This will list all commits which exist only on HEAD or on MERGE_HEAD,
- and which touch an unmerged file.
+ These will display all commits which exist only on HEAD or on
+ MERGE_HEAD, and which touch an unmerged file.
- We can now add the resolved version to the index and commit:
+ Each time you resolve the conflicts in a file and update the index:
-------------------------------------------------
$ git add file.txt
- $ git commit
-------------------------------------------------
- Note that the commit message will already be filled in for you with
- some information about the merge. Normally you can just use this
- default message unchanged, but you may add additional commentary of
- your own if desired.
+ the different stages of that file will be "collapsed", after which
+ git-diff will (by default) no longer show diffs for that file.
[[undoing-a-merge]]
undoing a merge
Or, if you've already commited the merge that you want to throw away,
-------------------------------------------------
- $ git reset --hard HEAD^
+ $ git reset --hard ORIG_HEAD
-------------------------------------------------
However, this last command can be dangerous in some cases--never
conflicts manually, just as in the case of <<resolving-a-merge,
resolving a merge>>.
+ [[fixing-a-mistake-by-editing-history]]
Fixing a mistake by editing history
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
$ git rebase --abort
-------------------------------------------------
+ Modifying a single commit
+ -------------------------
+
+ We saw in <<fixing-a-mistake-by-editing-history>> that you can replace the
+ most recent commit using
+
+ -------------------------------------------------
+ $ git commit --amend
+ -------------------------------------------------
+
+ which will replace the old commit by a new commit incorporating your
+ changes, giving you a chance to edit the old commit message first.
+
+ You can also use a combination of this and gitlink:git-rebase[1] to edit
+ commits further back in your history. First, tag the problematic commit with
+
+ -------------------------------------------------
+ $ git tag bad mywork~5
+ -------------------------------------------------
+
+ (Either gitk or git-log may be useful for finding the commit.)
+
+ Then check out a new branch at that commit, edit it, and rebase the rest of
+ the series on top of it:
+
+ -------------------------------------------------
+ $ git checkout -b TMP bad
+ $ # make changes here and update the index
+ $ git commit --amend
+ $ git rebase --onto TMP bad mywork
+ -------------------------------------------------
+
+ When you're done, you'll be left with mywork checked out, with the top patches
+ on mywork reapplied on top of the modified commit you created in TMP. You can
+ then clean up with
+
+ -------------------------------------------------
+ $ git branch -d TMP
+ $ git tag -d bad
+ -------------------------------------------------
+
+ Note that the immutable nature of git history means that you haven't really
+ "modified" existing commits; instead, you have replaced the old commits with
+ new commits having new object names.
+
Reordering or selecting from a patch series
-------------------------------------------
options mentioned above.
+ [[git-internals]]
Git internals
=============
$ git-merge-index git-merge-one-file hello.c
-------------------------------------------------
-and that is what higher level `git resolve` is implemented with.
+and that is what higher level `git merge -s resolve` is implemented with.
How git stores objects efficiently: pack files
----------------------------------------------
Simplify beginning by suggesting disconnected head instead of
temporary branch creation?
- Explain how to refer to file stages in the "how to resolve a merge"
- section: diff -1, -2, -3, --ours, --theirs :1:/path notation. The
- "git ls-files --unmerged --stage" thing is sorta useful too,
- actually. And note gitk --merge.
-
Add more good examples. Entire sections of just cookbook examples
might be a good idea; maybe make an "advanced examples" section a
standard end-of-chapter section?