User Tools

Site Tools


quickref:git

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
Last revision Both sides next revision
quickref:git [2013/08/19 15:50]
andy Fixed a bunch of double-dashes I'd forgotten to escape.
quickref:git [2014/12/18 12:46]
andy Added some recipes, updated gitconfig file
Line 8: Line 8:
  
 If you're not already moderately familiar with Git, strongly consider browsing the [[#Git Structure]] section first as it can make Git operations easier to understand. If you're not already moderately familiar with Git, strongly consider browsing the [[#Git Structure]] section first as it can make Git operations easier to understand.
 +
 +If you're just looking for some handy commands, check out the [[#​Recipes]] section.
  
  
Line 916: Line 918:
  
 Commands such as ''​git log''​ operate on a set of commits, not just a single one. To that end, the syntax for [[#single revisions]] is augmented in various ways to allow the specification of a range of commits: Commands such as ''​git log''​ operate on a set of commits, not just a single one. To that end, the syntax for [[#single revisions]] is augmented in various ways to allow the specification of a range of commits:
 +
 +<​note>​The syntax used by ''​git diff''​ appears superficially similar but is //not// the same!</​note>​
  
 ^ Method ^ Example ^ Explanation ^ ^ Method ^ Example ^ Explanation ^
Line 1018: Line 1022:
 ==== git diff ==== ==== git diff ====
  
-The ''​git diff''​ command is used to show differences between files in various locations. This is similar to ''​git log''​ in some ways, although ''​git diff''​ compares the differences in the endpoints rather than examining the full commit history. As a result, ​it doesn'​t accept ​the full set of [[#Revision Ranges|ranges]] ​that ''​git log'' ​does.+The ''​git diff''​ command is used to show differences between files in various locations. This is similar to ''​git log''​ in some ways, although ''​git diff''​ compares the differences in the endpoints rather than examining the full commit history. As a result, ​while the syntax appears superficially similar ​the [[#Revision Ranges|ranges]] ​used by ''​git log''​, the interpretations differ.
  
 The possible invocations are: The possible invocations are:
  
 ^ ''​%%git diff%%''​ | Show the differences between the current working directory and the index. | ^ ''​%%git diff%%''​ | Show the differences between the current working directory and the index. |
-^ ''​%%git diff <​commit>​%%''​ | As ''​git diff'',​ but compare to the named commit instead of the index. | +^ ''​%%git diff <​commit>​%%''​ | As ''​git diff'',​ but compare ​the working directory ​to the named commit instead of the index\\ (e.g. ''​git diff HEAD''​ to compare to most recent commit on the current branch). | 
-^ ''​%%git diff --cached%%''​ | Show the differences between the index and the current HEAD.\\ Optionally, a different commit than than the HEAD can be specified. | +^ ''​%%git diff --cached ​[<​commit>​]%%''​ | Show the differences between the index and the current HEAD.\\ Optionally, a different commit than than the HEAD can be specified. | 
-^ ''​%%git diff <src-commit> <dst-commit>​%%''​\\ ''​%%git diff <src-commit>​..<​dst-commit>​%%''​ | Show differences between two arbitrary commits (the two forms are equivalent).\\ Omitting either commit causes Git to assume ''​HEAD''​. | +^ ''​%%git diff <from-commit> <to-commit>​%%''​\\ ''​%%git diff <from-commit>​..<​to-commit>​%%''​ | Show differences between two arbitrary commits (the two forms are equivalent).\\ Omitting either commit ​in the latter form causes Git to assume ''​HEAD'' ​for it. | 
-^ ''​%%git diff <src-commit>​...<​dst-commit>​%%''​ | Show differences between the common ancestor of both commits and ''<​dst-commit>''​.\\ Omitting either commit causes Git to assume ''​HEAD''​. |+^ ''​%%git diff <from-commit>​...<​to-commit>​%%''​ | Show differences between the common ancestor of both commits and ''<​to-commit>''​.\\ Omitting either commit causes Git to assume ''​HEAD''​. |
  
 As with ''​git log'',​ it's possible to supply one or more paths to filter the files diffed: As with ''​git log'',​ it's possible to supply one or more paths to filter the files diffed:
Line 1148: Line 1152:
  
 Once this file is saved, Git proceeds with the rebase as normal. Conflicts are handled as per a [[#​Rebasing|standard rebase]] and the ''​edit''​ action will also require the use of ''​%%git rebase --continue%%''​ to carry on the rebase operation. Once this file is saved, Git proceeds with the rebase as normal. Conflicts are handled as per a [[#​Rebasing|standard rebase]] and the ''​edit''​ action will also require the use of ''​%%git rebase --continue%%''​ to carry on the rebase operation.
 +
 +
 +==== Squash Merges ====
 +
 +Similar in some ways to the ''​squash''​ option of interactive rebasing is the ''​%%--squash%%''​ option to ''​git merge''​. This allows multiple commits to be merged into a single commit on a different branch. The primary difference is that an interactive rebase modifies a source branch such that the destination could be fast-forwarded to it, whereas a squashing merge will create an entirely new commit on the destination branch which is the combination of all the source commits, leaving the individual commits intact on the source branch.
 +
 +The syntax is the same as for a standard ''​git merge''​ with the addition of the ''​%%--squash%%''​ parameter. The result is that the index (only) is updated with the combination of all the source commits, so it differs from a standard merge in that this must then be committed to the repository with ''​git commit''​. In this way merges from multiple branches may be squashed together by repeated executions of ''​%%git merge --squash%%''​ prior to the ''​git commit''​. Any conflicts will be flagged and must be resolved as with a standard merge before continuing.
 +
 +Once the commit is done, the history of each source branch is left untouched and a new commit will have been created on the destination branch which is the combination of the selected commits. The source and destination branches will have effectively diverged. The situation will be something like the following example, which assumes that other commits have been made to ''​master''​ before doing the merge.
 +
 +<​graphviz>​
 +digraph G {
 +  graph [dpi=60];
 +  node [shape=box style="​filled,​rounded"​ color="​black"​ fontcolor="​black"​ fillcolor=lightgrey];​
 +  {rank="​same";​ merged -> commit7 -> commit6 -> commit3 -> commit2 -> commit1;}
 +  {rank="​same";​ commit5 -> commit4;}
 +  commit4 -> commit3;
 +  commit6 -> commit4 [style="​invis"​ weight=999];​
 +  commit7 -> commit5 [style="​invis"​ weight=999];​
 +  commit5 -> merged [style=dashed];​
 +  commit4 -> merged [style=dashed];​
 +  node [shape=box style="​filled,​rounded"​ color="​black"​ fontcolor="​black"​ fillcolor="#​eeeecc"​];​
 +  {rank="​same";​ master; "​feature-x"​}
 +  master -> merged;
 +  "​feature-x"​ -> commit5;
 +  node [shape=box style="​filled,​rounded"​ color="​black"​ fontcolor="​black"​ fillcolor="#​cceeee"​];​
 +  HEAD -> master;
 +}
 +</​graphviz>​
 +
 +As can be seen, the source branch is intact and could be left in existence as required, but unlike a rebase its commits haven'​t become part of the history of the destination branch so future merges may well produce conflicts. It's also worth noting that, unlike a standard merge, the final commit(s) on the branch(es) do //not// become parents of the mainline commit. The merged commit could have equally been created by manually applying the diffs of each source commit and an entirely new commit created.
  
 ===== Remote Repositories ===== ===== Remote Repositories =====
Line 1259: Line 1294:
 </​code>​ </​code>​
  
-The arguments may be omitted if the current branch is a **tracking branch**, and this would cause the remote ​branch tied to the current tracking branch to be used.+The arguments may be omitted if the current branch is a **tracking branch**, and this would cause the **upstream ​branch** tied to the current tracking branch to be used. To set this upstream the ''​%%git branch --set-upstream%%''​ command can be used, but often it's more convenient to specify the ''​%%-u%%''​ option to ''​git push'':​ 
 + 
 +<​code>​ 
 +git push -u <​remote>​ <​branch>​ 
 +</​code>​
  
-The ''<​branch>''​ specification above is actually a shorthand for the full specification:​+The ''<​branch>''​ specification above assumes that the branch name is the same on both repositories and is actually a shorthand for the full specification:​
  
 <​code>​ <​code>​
Line 1267: Line 1306:
 </​code>​ </​code>​
  
-The ''<​local branch>''​ here is typically a local branch, but could be any commit specification. The ''<​remote branch>''​ must be a real branch, however.+The ''<​local branch>''​ here is typically a local branch ​name, but could be any commit specification ​(e.g. a SHA1 hash). The ''<​remote branch>''​ must be a real branch, however, to avoid creation of a **detached head**, but if a non-existent branch is specified then it will be created based on the source branch. 
 + 
 +<note important>​It'​s worth noting that this point that you should avoid modifying changes (for example, via an interactive rebase) once they'​ve been pushed or pulled to another repository unless you maintain both and are prepared to deal with the resultant conflicts.</​note>​
  
 Normally the push operation fails if the remote merge operation is anything other than a **fast-forward** (i.e. the local repository has already merged all of the remote changes). If this is not the case, it will exit with an appropriate error and the remote changes will need to be merged locally first. If the branch specification is prefixed with ''​+'',​ the update will be done even if the merge is not a fast-forward. Normally the push operation fails if the remote merge operation is anything other than a **fast-forward** (i.e. the local repository has already merged all of the remote changes). If this is not the case, it will exit with an appropriate error and the remote changes will need to be merged locally first. If the branch specification is prefixed with ''​+'',​ the update will be done even if the merge is not a fast-forward.
Line 1282: Line 1323:
  
 As a special case, leaving both ''<​local branch>''​ and ''<​remote branch>''​ empty will push changes between all "​matching"​ branches --- i.e. for each local branch, a remote branch of the same name is updated if it already exists. As a special case, leaving both ''<​local branch>''​ and ''<​remote branch>''​ empty will push changes between all "​matching"​ branches --- i.e. for each local branch, a remote branch of the same name is updated if it already exists.
- 
  
 ===== Diffcore ===== ===== Diffcore =====
Line 1991: Line 2031:
  
 <file - .gitconfig>​ <file - .gitconfig>​
-[user] +        ​name = Andy Pearce
- name = Andy Pearce +
- email = andy@andy-pearce.com+
 [merge] [merge]
- conflictstyle ​diff3 +        tool vimdiff 
- tool meld+        ​defaultToUpstream ​true
 [diff] [diff]
- tool = meld+        ​tool = vimdiff
 [color] [color]
- ui = true+        ​ui = true
 [color "​branch"​] [color "​branch"​]
- current = green bold +        ​current = green bold 
- local = green +        local = green 
- remote = blue +        remote = black bold 
- plain = red+        plain = red
 [color "​diff"​] [color "​diff"​]
- plain = white +        ​plain = white 
- meta = white blue bold +        meta = yellow ​blue bold 
- frag = blue bold +        frag = white blue bold 
- func = blue bold +        func = white blue 
- old = red bold +        old = red 
- new = green bold +        new = green 
- commit = white bold +        commit = yellow 
- whitespace = white red+        whitespace = red reverse
 [color "​decorate"​] [color "​decorate"​]
- branch = green +        ​branch = green 
- remoteBranch = blue +        remoteBranch = black bold 
- tag = red +        tag = red 
- stash = cyan +        stash = blue bold 
- HEAD = yellow+        HEAD = yellow ​bold
 [color "​grep"​] [color "​grep"​]
- context = cyan +        ​context = cyan 
- filename = magenta +        filename = magenta 
- function = white blue bold +        function = white blue bold 
- linenumber = green +        linenumber = green 
- match = yellow bold +        match = yellow bold 
- selected = white +        selected = white 
- separator = cyan+        separator = cyan
 [color "​interactive"​] [color "​interactive"​]
- prompt = white bold +        ​prompt = white bold 
- header = blue bold +        header = blue bold 
- help = green +        help = green 
- error = red bold+        error = red bold
 [color "​status"​] [color "​status"​]
- header = blue bold +        ​header = blue bold 
- added = green +        added = green 
- updated = green +        updated = green 
- changed = red bold +        changed = red bold 
- untracked = cyan +        untracked = cyan 
- branch = green bold +        branch = green bold 
- nobranch = white red bold+        nobranch = white red bold 
 +[init] 
 +        templatedir = /​home/​apearce16/​.git_template 
 +[alias] 
 +        aliases = "!git config --list | grep ^alias"​ 
 +        branches = for-each-ref --sort=-committerdate --format='​%(color:​cyan)|%(committerdate:​relative)| %(color:​yellow bold)%(refname:​short)'​ refs/​heads 
 +        branchgraph = log --graph --abbrev-commit --decorate --simplify-by-decoration --date=relative --all --pretty=format:"​%C(yellow)%h\\ %C(cyan)|%ad|%C(yellow)%C(bold)%d\\ %Creset%s%C(green)\\ [%an]%C(blue)%C(bold)\\ <​%cn>"​ 
 +        branchhistory = "!git showline HEAD; git showline @{-1}; git showline @{-2}; git showline @{-3}; git showline @{-4}; git showline @{-5}"​ 
 +        changed = diff-tree -r --no-commit-id --name-only --relative 
 +        changes = log --pretty=format:"​%C(yellow)%h\\ %C(cyan)|%ad|%C(yellow)%C(bold)%d\\ %Creset%s%C(green)\\ [%an]%C(blue)%C(bold)\\ <​%cn>"​ --decorate --stat --date=relative 
 +        commits = log --pretty=format:"​%C(yellow)%h\\ %C(cyan)|%ad|%C(yellow)%C(bold)%d\\ %Creset%s%C(green)\\ [%an]%C(blue)%C(bold)\\ <​%cn>"​ --decorate --date=relative 
 +        ctags = !.git/​hooks/​ctags 
 +        fe = fetch --prune 
 +        ff = merge --ff-only 
 +        graph = log --graph --abbrev-commit --decorate --date=relative --all --pretty=format:"​%C(yellow)%h\\ %C(cyan)|%ad|%C(yellow)%C(bold)%d\\ %Creset%s%C(green)\\ [%an]%C(blue)%C(bold)\\ <​%cn>"​ 
 +        grepall = "!git grep --full-name -n -p" 
 +        showline = log --oneline --decorate -1 
 +        summary = show --name-status 
 +[push] 
 +        default = upstream 
 +[rebase] 
 +        autosquash = true 
 + 
 +[difftool] 
 +        prompt = false
 </​file>​ </​file>​
  
Line 2057: Line 2119:
 </​file>​ </​file>​
  
 +===== Recipes =====
 +
 +The following are some handy pre-canned commands for specific situations. You can set up [[https://​git.wiki.kernel.org/​index.php/​Aliases|aliases]] for these as well.
 +
 +==== Housekeeping ====
 +
 +A good couple of aliases to run in quick succession to fetch remotes with pruning, and then fast-forward the current branch if possible:
 +
 +<​code>​
 +git fetch --prune
 +git merge --ff-only
 +</​code>​
 +
 +
 +==== Searching ====
 +
 +Search the entire repository, regardless of the current subdirectory:​
 +
 +<​code>​
 +git grep --full-name -n -p <​needle>​
 +</​code>​
 +
 +
 +==== Listing commits ====
 +
 +Show recent commits with relative dates and authors:
 +
 +<​code>​
 +git log --decorate --date=relative \
 +        --pretty=format:"​%C(yellow)%h %C(cyan)|%ad|%C(yellow)%C(bold)%d %Creset%s%C(green) [%an]%C(blue)%C(bold) <​%cn>"​
 +</​code>​
 +
 +Show the history of a specified file:
 +
 +<​code>​
 +git log -p -- <​filename>​
 +</​code>​
 +
 +Show a graph of all commits:
 +
 +<​code>​
 +git log --graph --abbrev-commit --decorate --date=relative --all \
 +        --pretty=format:"​%C(yellow)%h %C(cyan)|%ad|%C(yellow)%C(bold)%d %Creset%s%C(green) [%an]%C(blue)%C(bold) <​%cn>"​
 +</​code>​
 +
 +As above, but only commits which are the head of a branch:
 +
 +<​code>​
 +git log --pretty=format:"​%C(yellow)%h %C(cyan)|%ad|%C(yellow)%C(bold)%d %Creset%s%C(green) [%an]%C(blue)%C(bold) <​%cn>"​ \
 +        --graph --abbrev-commit --decorate --simplify-by-decoration --date=relative --all 
 +</​code>​
 +
 +
 +==== Listing Files ====
 +
 +Show files that changed between two commits in the current directory:
 +
 +<​code>​
 +git diff-tree -r --no-commit-id --name-only --relative <​commit1>​ <​commit2>​
 +</​code>​
 +
 +
 +==== Listing Branches ====
 +
 +List branches in order of last commit time, most recent first (useful for removing dead branches):
 +
 +<​code>​
 +git for-each-ref --sort=-committerdate \
 +                 ​--format='​%(color:​cyan)|%(committerdate:​relative)| %(color:​yellow bold)%(refname:​short)'​ \
 +                 ​refs/​heads
 +</​code>​
  
quickref/git.txt · Last modified: 2015/07/02 11:36 by andy