├── archived ├── branches.mkd ├── corruption.mkd ├── cvs2git.mkd ├── grafting.mkd ├── hg.mkd ├── ignore-upstream-commit.mkd ├── index.mkd ├── links.mkd ├── special-branch-fixups.mkd ├── special-branches.mkd ├── svn.mkd ├── vss2git.mkd ├── whitespace-index-filter.mkd └── workflow-integ-devs.mkd ├── articles ├── articles.mkd ├── blame-detection-and-C-levels.mkd ├── deploy.mkd ├── detached-head.mkd ├── git-over-proxy.mkd ├── git-performance.mkd ├── git-pull--rebase.mkd ├── gitk.mkd ├── ignore-rules.mkd ├── reflog.mkd ├── server-sizing.mkd ├── tias.mkd ├── uses-of-index.mkd └── vc-habits.mkd ├── common-header.html ├── grafts.todo ├── images ├── corporate-use-1.gv ├── corporate-use-2.gv ├── corporate-use-3.gv ├── corporate-use-4.gv ├── corporate-use-5.gv ├── corporate-use-6.gv ├── git.png ├── git │ ├── demo-09-01.png │ ├── demo-09-02.png │ ├── demo-09-03.png │ ├── demo-09-04.png │ ├── demo-09-05.png │ ├── demo-09-06.png │ ├── demo-09-07.png │ ├── demo-09-08.png │ ├── demo-09-09.png │ ├── demo-09-10.png │ ├── demo-09-11.png │ ├── demo-10-01.png │ ├── demo-10-02.png │ ├── demo-10-03.png │ ├── demo-11-01.png │ ├── demo-11-02.png │ ├── demo-11-03.png │ ├── demo-11-04.png │ ├── demo-11-05.png │ ├── demo-11-06.png │ ├── demo-12-01.png │ ├── demo-12-02.png │ ├── demo-12-03.png │ ├── demo-12-04.png │ ├── demo-12-05.png │ ├── demo-13-01.png │ ├── demo-13-02.png │ ├── demo-13-03.png │ ├── flow-CVCS.svg │ ├── flow-DVCS.svg │ ├── flow-Git.svg │ ├── gitk-1.png │ ├── gitk-2.png │ ├── gitk-3.png │ ├── gui-blame-1.png │ ├── gui-blame-2.png │ ├── gui-blame-3.png │ ├── gui-blame-4.png │ ├── gui-blame-5.png │ └── projects-sans-vcs.png ├── gitlfy-fig1-gui-blame.gif ├── gitlfy-fig2-branch-visual.gif ├── gitlfy-fig3-stitching-pattern.gif ├── index-use-review-1.svg ├── index-use-review-2.svg ├── index-use-review-3.svg ├── index-use-review-4.svg ├── server.png ├── vc │ ├── clean-again.png │ ├── clean-cli.png │ ├── clean-gui.png │ ├── commit-gui.png │ ├── dag-br-tag.png │ ├── dag-br.png │ ├── dag.png │ ├── dirty-cli.png │ ├── dirty-gui.png │ ├── empty-windows.png │ ├── empty.png │ ├── init-done-win1.png │ ├── init-done-win2.png │ ├── init-done-winb.png │ ├── init-done.png │ ├── init-win1.png │ ├── init-win2.png │ ├── init-win3.png │ ├── init-win4.png │ ├── init-winb1.png │ ├── init-winb2.png │ ├── inside-dotgit.png │ ├── remote.png │ ├── repo-1.png │ ├── repo-2.png │ ├── repo-3.png │ ├── repo-4.png │ ├── repo-5.png │ ├── repo-6.png │ ├── repo.png │ ├── sampleproj.png │ ├── staged-cli.png │ ├── staging-gui.png │ ├── worktree-symbol.png │ └── worktree.png └── workstation_t.png ├── index.html ├── index2.mkd ├── license.mkd ├── mkdoc ├── tools ├── git-reflogk └── vss2git.pl ├── usage ├── commands.mkd ├── gotchas-cli.mkd ├── gui.mkd ├── legacy.mkd ├── server.mkd ├── tips-1.mkd ├── tips-2.mkd ├── tips-3.mkd ├── usage.mkd └── windows.mkd ├── what ├── gcs.mkd ├── git.mkd ├── terminology.mkd └── vc.mkd └── why └── git-lfy.mkd /archived/branches.mkd: -------------------------------------------------------------------------------- 1 | % all about branches and product maintenance 2 | 3 | **CVS/SVN folks -- please read this first** 4 | 5 | SVN and CVS treat a branch as another subdirectory of your project. 6 | Conversely, you can also pretend a subdirectory is a branch. In other words, 7 | branches (and tags) share the same namespace as the subdirectories of your 8 | project. 9 | 10 | This is not the right way to think of branches. **A branch is merely an 11 | alternate reality for your project**. That's the simplest way to put it. 12 | Each commit is a "snapshot" of the state of your code at a certain point in 13 | time, and each branch (consisting of a series of commits) represents a 14 | different timeline than the other branches do. 15 | 16 | Thus, branches and subdirectories have *nothing* to do with each other. 17 | 18 | ---- 19 | 20 | # local and remote branches 21 | 22 | The git repository is really just a DAG (directed acyclic graph) of commits. 23 | Each commits points to its parent or parents (merge commits have more than one 24 | parent). A branch in git is merely a pointer to some commit in the DAG. 25 | 26 | When you checkout a branch, git simply makes your working tree look like the 27 | files that existed when that commit was made, and makes a note that this is 28 | your "current" branch. When you make a commit on top of this, git updates 29 | this current branch to point to the new "head" commit. This is conceptually 30 | the same as adding a new item to a linked list and moving the "head" pointer 31 | to the new item, if you remember your data structures course from many years 32 | ago. 33 | 34 | A developer's repository will typically have several branches residing in it, 35 | although of course only one is "checked out" at any given time into the 36 | working tree. 37 | 38 | Apart from local branches (like `master`, `next`, and maybe `v1.2`, 39 | `some-new-feature`), etc., you will also have a set of branches called 40 | **origin/branchname** (example: `origin/master`). These are *your copy* of 41 | the corresponding branch from the "origin" server. You should never commit to 42 | them directly. 43 | 44 | And the most important thing is, you can have any other branches you wish! Go 45 | wild -- no one will stop you, and it's quite difficult to lose data so have 46 | fun! 47 | 48 | # topic branches 49 | 50 | As you read about workflows in modern VCSs, you'll often hear about topic 51 | branches. According to the [git 52 | glossary](http://www.kernel.org/pub/software/scm/git/docs/gitglossary.html#def_topic_branch), 53 | a topic branch is: 54 | 55 | > *A regular git branch that is used by a developer to identify a conceptual 56 | line of development. Since branches are very easy and inexpensive, it is 57 | often desirable to have several small branches that each contain very well 58 | defined concepts or small incremental yet related changes.* 59 | 60 | A topic branch could represent any self-contained, pretty much 61 | independent-of-others, line of development. A specific bug, a new feature, a 62 | refactor, a set of enhancements to a core feature, etc., can all be managed as 63 | topics in their own right. 64 | 65 | # product maintenance 66 | 67 | Let's say your version tree looks like this: 68 | 69 | V3---o---o---o---o---o---V4---o---o--- (master) 70 | \ \ 71 | \---o---o--- (V3maint) \ 72 | \ \---o---o--- (V4maint) 73 | \-o--- (topicA) \ 74 | \-o--- (topicB) 75 | 76 | In this picture, V3 and V4 are tags representing specific versions. V3maint 77 | is a maintenance branch that collects ongoing fixes for V3. These ongoing 78 | fixes could come from commits within V3maint itself, or by integrating topic 79 | branches such as topicA. At various points in it's lifecycle, when things are 80 | stable, the top commit on V3maint will be tagged V3.1, V3.2, etc., as needed. 81 | 82 | (...all this applies equivalently to V4 also, of course...) 83 | 84 | The "master" branch is where on-going development for the future V5 is 85 | happening. This "new" development may well have its own set of topic 86 | branches, probably by feature name, but right now we'll concentrate on the 87 | maintenance aspect of fixing bugs or making enhancements to the released 88 | versions. 89 | 90 | The simplest way to manage the flow of patches and fixes is this: 91 | 92 | * when a change is small enough to not need a topic branch, ***commit it on 93 | the oldest branch that needs the change***. In this example, that could 94 | be the V3maint or V4maint branch, depending on whether the issue affects 95 | V3 or not. 96 | 97 | Note that you **cannot commit on V3**. V3 is a tag -- a tag represents a 98 | "fixed point" in the commit hierarchy -- it's value can't change. You can 99 | only commit on a "branch". In C terms, a tag is a `const` :-) 100 | 101 | Also, note that although V3maint is primarily an integration branch for 102 | the topic branches pertaining to V3, in this case it is acting as a 103 | "catchall" topic branch for commits that are too small to have their own 104 | topics. 105 | 106 | * for larger changes, create a topic branch by making a ***fork at the 107 | oldest branch that needs this change***. For a bug that is applicable to 108 | V4 but not to V3, you'd fork a topic branch at V4. On the other hand, if 109 | the bug applies to V3 also, you'd fork at V3. 110 | 111 | *Note* that you're *not* forking at V3maint or V4maint; you're forking at 112 | V3 or V4. See discussion in the previous bullet about V3maint's role. 113 | 114 | However, it may sometimes happen that the bug does not apply to V3 but 115 | *only* to V3maint (perhaps it's a bug that was caused by some previous fix 116 | within the V3maint branch). In that case, you must commit/fork it at the 117 | current tip of V3maint. 118 | 119 | * Periodically ***merge the older branches into newer ones*** so the new 120 | branches get the benefit of accumulated fixes and enhancements on the 121 | older branches. This means, for instance, that we merge V3maint, as well 122 | as topic branches that forked from V3 (like topicA), into V4maint, and 123 | then V4maint, (plus topics like topicB) into "master", which is the future 124 | V5, etc. 125 | 126 | The exception to these rules is if you have bugs on older versions that do not 127 | apply to newer versions. Merging fixes that are relevant *only* to V3, into 128 | the V4 branch, is meaningless, and may even get you conflicts. The way to 129 | deal with those is as follows: 130 | 131 | * create a new branch called, say, V3only, forked from V3 132 | * fixes that apply *only* to V3 go on V3only 133 | * fixes that apply *from* V3, to all future versions, go on V3maint 134 | * periodically, V3maint is merged into both V4maint as well as to V3only 135 | 136 | Note that V3only will never get merged into V4maint or V3maint, preserving the 137 | condition that commits made in V3only are not picked up by the newer versions. 138 | 139 | # throwaway integration branches 140 | 141 | In all the above discussion, we kept saying "merge X into Y". Which is all 142 | very well if things go fine, but how do you back out if something went wrong? 143 | 144 | The answer is something called a "throwaway integration branch". 145 | 146 | We'll use an analogy to understand this. Let's say you're writing a function 147 | to insert a bunch of items into a linked list. And let's say it's a complex 148 | function, and at the start, you're not sure if it's going to succeed, and you 149 | want the "head" pointer to be updated only if the whole thing succeeds. 150 | 151 | How would you deal with this? You'd make a temporary copy of the "head" 152 | pointer, use that in your function, and if the function returns a success 153 | value, you'd update the real "head" pointer. Conversely, if the function 154 | returned an error, you would leave your real "head" pointer as it is and just 155 | discard the temporary value. 156 | 157 | Git makes creating a new branch just as easy. So instead of doing this: 158 | 159 | git checkout V4maint 160 | git merge V3maint # what if merge fails? 161 | make test # what if merge succeeds but tests fail? 162 | 163 | where if either of the last 2 steps fail, you have to figure out how to get 164 | back to the old V4, you do this instead: 165 | 166 | git branch -f test V4maint # forcibly set test branch to V4 167 | git checkout test # and check it out 168 | git merge V3maint 169 | make test 170 | # all good? 171 | git branch -f V4maint test # forcibly set V4maint to test 172 | 173 | And of course if things didn't work out you would not do that last step, 174 | preserving your V4maint at its previous revision. 175 | -------------------------------------------------------------------------------- /archived/corruption.mkd: -------------------------------------------------------------------------------- 1 | % corruption in a git repository 2 | 3 | For now, this is just loosely formatted text, maybe like a series of case 4 | studies. 5 | 6 | IMPORTANT NOTE: `git fsck --full` is needed to reliably find repo corruption 7 | 8 | # case 1: Kolkata Korruption -- 2 missing tree objects 9 | 10 | what finally worked: 11 | 12 | # on some good repo 13 | TYPE=$(git cat-file -t $BADOBJSHA) 14 | git cat-file $TYPE $BADOBJSHA > file 15 | 16 | # copy file to bad repo 17 | git hash-object -t $TYPE -w --stdin < file 18 | 19 | However, this may not always work; it is not certain that hash-object will 20 | *replace* a corrupted object (as opposed to creating a *missing* object). So 21 | try that, *as well as* this (generic object): 22 | 23 | # on some good repo 24 | echo $object | git pack-objects --revs pack 25 | # will create two files named pack-*.{idx,pack} 26 | 27 | confirm: 28 | 29 | git verify-pack -v pack-*.idx | grep $object 30 | # should also contain all sub objects 31 | 32 | copy: 33 | 34 | pack* to $bad_repo/[.git?]/objects/pack 35 | 36 | repack: 37 | 38 | repack -a -d 39 | 40 | (you could also do "unpack-objects" I guess) 41 | -------------------------------------------------------------------------------- /archived/cvs2git.mkd: -------------------------------------------------------------------------------- 1 | % converting CVS to git 2 | 3 | Update 2009-10-08: It has been pointed out that cvsimport, which I recommend 4 | against using below, can do incremental imports. If this is important to you 5 | (it wasn't, to me, and it never will be), then this document is probably no 6 | use to you. Sorry... 7 | 8 | ---- 9 | 10 | First: do **NOT** use the builtin `git cvsimport` unless your repository is 11 | very simple and linear. Problems I had using it on a moderately complex repo 12 | include missing tags, branches grafted to the wrong place (by comparing with a 13 | `--simplify-by-decoration` tree later), missing commits (which is what 14 | originally made me start investigating), and even missing files in the root of 15 | the repo!! 16 | 17 | It's been too long since I last used CVS to figure this out, and cvs2svn 18 | seemed to deal with a lot more nuances, so I used that instead. 19 | 20 | # step 1 -- make a dump file 21 | 22 | * download cvs2svn version 2.1 or higher from somewhere within 23 | . DO NOT BE DISTRACTED BY THE 24 | MISLEADING REFERENCES TO A MYTHICAL `cvs2git` COMMAND IN THAT PAGE :) As 25 | of the time I tried this, it didn't exist. Maybe now it does... 26 | 27 | * expand it somewhere, and cd there 28 | 29 | * in there, create an options file from the original, like shown in the 30 | [patch](#patch) at the end of this file (change accordingly of course; 31 | this diff only shows where you should make the changes, not what) 32 | 33 | **IMPORTANT WARNING** 34 | 35 | DO NOT USE the `test-data/main-cvsrepos/cvs2svn-git.options` file as a 36 | starting point. Though the intermediate files were about 3X smaller when 37 | I used it, there were lots of inaccuracies w.r.t the $id type stuff, and 38 | for some older tags whole files were missing, compared to the 39 | corresponding CVS checkout. The `-inline` version seems to work fine; no 40 | errors on any of the 30 or so tags I checked on a project that had about 5 41 | years of work in CVS. 42 | 43 | - run 44 | 45 | ./cvs2svn --options=my.c2soptions 46 | 47 | - when it completes, check the `cvs2svn-tmp` directory for a rather large 48 | file called git-dump.dat 49 | 50 | # step 2 -- import into git 51 | 52 | - make an empty directory, cd to it, git init, then run 53 | 54 | cat ~-/cvs2svn-tmp/git-dump.dat | git fast-import 55 | 56 | - if you used the non-inline options file, or wanted to test that as well, 57 | there would be *two* files in the cvs2svn-tmp directory, and the command 58 | would now be: 59 | 60 | cat ~-/cvs2svn-tmp/git-{blob,dump}.dat | git fast-import 61 | 62 | # Appendix {#patch} 63 | 64 | These are the changes I made to the options file: 65 | 66 | diff --git 1/test-data/main-cvsrepos/cvs2svn-git-inline.options 2/my.c2soptions.inline 67 | index 635f9cd..a5a4018 100644 68 | --- 1/test-data/main-cvsrepos/cvs2svn-git-inline.options 69 | +++ 2/my.c2soptions.inline 70 | @@ -39,7 +39,7 @@ ctx.cross_branch_commits = False 71 | # record the original author (for example, the creation of a branch). 72 | # This should be a simple (unix-style) username, but it can be 73 | # translated into a git-style name by the author_transforms map. 74 | -ctx.username = 'cvs2svn' 75 | +ctx.username = 'someone' 76 | 77 | # CVS uses unix login names as author names whereas git requires 78 | # author names to be of the form "foo ". The default is to set 79 | @@ -59,7 +59,7 @@ author_transforms={ 80 | 81 | # This one will be used for commits for which CVS doesn't record 82 | # the original author, as explained above. 83 | - 'cvs2svn' : ('cvs2svn', 'admin@example.com'), 84 | + 'someone' : ('someone', 'someone@my.company.com'), 85 | } 86 | 87 | # This is the main option that causes cvs2svn to output to git rather 88 | @@ -115,7 +115,7 @@ run_options.add_project( 89 | # The path to the part of the CVS repository (*not* a CVS working 90 | # copy) that should be converted. This may be a subdirectory 91 | # (i.e., a module) within a larger CVS repository. 92 | - r'test-data/main-cvsrepos', 93 | + r'../cvsroot/myproj', 94 | 95 | # See cvs2svn-example.options for more documention about symbol 96 | # transforms that can be set using this option. 97 | -------------------------------------------------------------------------------- /archived/hg.mkd: -------------------------------------------------------------------------------- 1 | % for people who think Hg is just as good 2 | 3 | **Update: Dec 2013**. 4 | 5 | : Of all the stuff I dumped in the "archived/" directory, this is probably 6 | the most out of date. Over the last few years, Hg has, I think, managed 7 | to get rid of most of the early craziness with respect to branching 8 | (exacerbated by, in my *firm* opinion, a huge dollop of NIH syndrome!). 9 | 10 | I actually tried to learn it a couple of times, but gave up. I didn't see 11 | any real advantages to it, but more important, I find I get *seriously* 12 | turned off when I see tutorials conflating "branch" and "clone". 13 | 14 | ---- 15 | 16 | Hg is almost as good as git. Linus pretty much says so in his famous 17 | googletalk. 18 | 19 | Almost :-) 20 | 21 | Here're some links about Hg; detailed commentary from me may come later, but I 22 | doubt I will have the time or the inclination. It's not like this is SVN and 23 | I have to strenuously keep you away from it -- go ahead and use Hg if you like 24 | it and it fits your work style :-) 25 | 26 | Also, I have no intention of becoming an Hg expert to answer questions or 27 | criticisms about this page. If you think something is wrong, tell me and I'd 28 | be happy to update it. 29 | 30 | # Local branches 31 | 32 | Hg does not permit a quick experimental branch just to test some wild idea 33 | quickly. Check out the "Branch Management" section in 34 | . 35 | 36 | Read the last 3 paras of that section, at least. 37 | 38 | 55 | 56 | # Projects 57 | 58 | Mozilla: quote from 59 | : 60 | 61 | > *"As good, performant Win32 (and Mac and Linux) is a hard-requirement, Git 62 | lost in early Kombat rounds. This is unfortunate because (as we would soon 63 | find out), lots of issues with the other systems did "just work" in Git."* 64 | 65 | # Unsorted URLs 66 | 67 | * 68 | * : 69 | *I used to be more of a Mercurial guy, but there's just a moment (at least 70 | there was for me) where it all clicks and Git makes sense. Having your 71 | repository be just a giant DAG of commits is what you want -- forcing each 72 | fork in the road to live in its own separate repository is a pain and 73 | unnecessary.* 74 | -------------------------------------------------------------------------------- /archived/ignore-upstream-commit.mkd: -------------------------------------------------------------------------------- 1 | % ignoring an upstream commit permanently 2 | 3 | (untested) 4 | 5 | ...as usual, doener on irc, circa 2009-07-15 10:00 6 | 7 | ---- 8 | 9 | # problem 10 | 11 | A---B---C---D---E (master) 12 | \ 13 | X---X---V---X (upstream) 14 | 15 | You try to merge upstream to master and get a shitload of conflicts. 16 | 17 | "gitk --merge" tells you that commit V is "guilty" and is just a variation of, 18 | let's say, B (doesn't matter), that differs enough to cause those conflicts. 19 | 20 | You decide that you don't want V's version of the changes, now or in future. 21 | That is, though you will keep merging from upstream, you don't want to see "V" 22 | ever again. 23 | 24 | # assumption 25 | 26 | You never have to push this upstream; it's your private copy (think "customer 27 | specific branch") 28 | 29 | # caveats 30 | 31 | Eventually, something upstream will patch something from V, and since you 32 | don't have that particular set of code, you'll get a patch that cannot be 33 | applied. At that point you can repeat this method to discard *that* commit, 34 | or fix the conflicts somehow and move on. 35 | 36 | # the hard solution 37 | 38 | Fix all the conflicts and commit. For people still living in other version 39 | control systems :-) 40 | 41 | # the easy solution 42 | 43 | Create a branch from upstream where you revert V and merge that to master 44 | 45 | git checkout -b tmp upstream 46 | git revert V # produces commit "R" 47 | git checkout master 48 | git merge tmp # please also use -m to document this properly! 49 | git branch -d tmp 50 | 51 | A---B---C---D---E---M (master) 52 | \ / 53 | \ R 54 | \ / 55 | X---X---V---X (upstream) 56 | 57 | Next update from upstream will lead to: 58 | 59 | git merge upstream 60 | 61 | A---B---C---D---E---M---M2 (master) 62 | \ / / 63 | \ R / 64 | \ / / 65 | X---X---V---X---X (upstream) 66 | 67 | (and so on; you've essentially eliminated "V" forever in your branch). 68 | 69 | Note: doener calls this ugly, but I like this much better than the next one. 70 | First, this only uses porcelain, no plumbing. Second, the extra commit "R" 71 | makes it clear that something happened, even if the merge commit at "M" was 72 | not properly commented. 73 | 74 | # the hackish, low-level solution 75 | 76 | Don't use this if, like me, you're not comfortable with plumbing. This 77 | section is just for the record, and because the idea is very cool. 78 | Personally, I never use plumbing -- too many commands, too hard for me to 79 | understand, even more difficult (for me) to explain. 80 | 81 | Create a branch from upstream, and revert V 82 | 83 | git checkout -b tmp upstream 84 | git revert V 85 | 86 | Merge master to that: 87 | 88 | git merge master 89 | 90 | Hopefully, the revert as well as the merge went pretty much conflict-free now. 91 | So you have the merge result that you want in tmp. 92 | 93 | Now, create the real merge: 94 | 95 | git checkout master 96 | git merge upstream 97 | 98 | This will cause conflicts again, but instead of fixing them, you just re-use 99 | the merge result that you already have: 100 | 101 | git read-tree -u --reset tmp # This reads the tree of the previous merge and 102 | # puts it into the index and working tree 103 | 104 | git commit 105 | 106 | This leads to 107 | 108 | A---B---C---D---E---M (master) 109 | \ / 110 | X---X---V---X---- (upstream) 111 | 112 | And the next update then gives: 113 | 114 | A---B---C---D---E---M---M (master) 115 | \ / / 116 | X---X---V---X-------X (upstream) 117 | -------------------------------------------------------------------------------- /archived/index.mkd: -------------------------------------------------------------------------------- 1 | % archived articles 2 | 3 | .@red<**DISCLAIMER**>@ 4 | 5 | This directory has a bunch of stuff that I wrote a long time ago. When I 6 | cleaned up the whole site (Dec 2013) I did not have time to check each one 7 | out, verify if what they say still holds, and generally fix things up. 8 | 9 | Use your discretion in making use of this information. Stuff that is 10 | conceptual in nature is probably still true, while stuff that includes actual 11 | code or commands may need double checking. Git *has* changed a lot in the 12 | last few years! 13 | 14 | .#d 15 | 16 | **General** 17 | 18 | * A bunch of [links](links.html) of all kinds -- basic stuff/concepts, 19 | tutorials, stuff that refugees from legacy VCSs might need, digging into 20 | git/troubleshooting, and a whole bunch of advocacy links. 21 | 22 | **Branching and workflow** 23 | 24 | * [branches](branches.html) -- local, remote, and topic branches; 25 | maintenance branches, throwaway branches... 26 | * An article on [customer branches](special-branches.html), with a section 27 | on **SVN-itis** (conflating branch and subdirectory!) 28 | * one possible[workflow](workflow-integ-devs.html) for integrating N 29 | developers and 1 integrator, using [gitolite](../gitolite/index.html) 30 | 31 | .#d 32 | 33 | **Random technical notes** 34 | 35 | * [repo corruption](corruption.html) -- notes from something I did once for 36 | a work colleague and written down so I don't forget 37 | * notes on [grafting](grafting.html) in git 38 | * [ignoring an upstream commit permanently](ignore-upstream-commit.html) 39 | * Fixing [whitespace](whitespace-index-filter.html) errors 40 | 41 | **Other VCSs** 42 | 43 | * for people who thing [hg](hg.html) is just as good ;-) 44 | * For people who think [SVN](svn.html) is good enough. While the same title 45 | applied to Hg may sound a little harsh, I have no sympathy for people who 46 | still advocate SVN. The only thing that has changed in my stance is that 47 | in the early days I used to take issue with them, now I just ignore them. 48 | It's not even worth arguing about now. 49 | * [cvs to git](cvs2git.html) 50 | * converting [visual source shredder](vss2git.html) to git 51 | 52 | .#t 53 | 54 | -------------------------------------------------------------------------------- /archived/special-branch-fixups.mkd: -------------------------------------------------------------------------------- 1 | % fixing-up common and customer branches 2 | 3 | The following document explains how to maintain a 'common' branch, 4 | with one or more 'customer specific' branches that hang off of the 5 | common branch. The inspiration was a question about maintaining 6 | 'work' and 'home' configurations which differ slightly from a 7 | 'common' configuration, which leads to the same sort of problem. 8 | 9 | In an ideal world, you'd keep 'common' development in the 'common' branch, 10 | and 'customer specific' development in the corresponding customer branches. 11 | In the real world, often the separation was not done properly in advance, 12 | (maybe it was not known, or maybe for initial testing reasons it had to be 13 | done in one branch, or whatever), and so you now have a mix of 'common' and 14 | 'special' changes all together. 15 | 16 | **This article describes one way to 'fix up' such a mixed development into the 17 | proper form**. 18 | 19 | # The basic rules 20 | 21 | The basic rules are best described by Junio in 22 | 23 | 24 | * You make edits to common files only on the common branch. 25 | * You merge from common to deployment, never the other way. 26 | 27 | This document shows how one might do that. [Junio also helped 28 | with comments on a previous draft of this text. However, any 29 | errors or other problems that remain are mine.] 30 | 31 | # Terminology 32 | 33 | We use the following terminology: 34 | 35 | 'common' is the branch representing the base product. All 36 | regular customers get this version. 37 | 38 | 'special' is a branch for a specific customer. This customer 39 | needs changes unique to his environment, which should not be 40 | merged back into the common branch. However, this branch must 41 | regularly get the benefit of changes in the mainline 'common' 42 | branch. (This is the genesis of the two rules above). 43 | 44 | If you have more than one special customer the same logic 45 | will apply for each of them separately, although if you have 46 | too many such customers you may also want to look at [Never 47 | merging back](http://gitster.livejournal.com/26540.html) 48 | for an additional tip on this. 49 | 50 | # The nitty gritty 51 | 52 | ## Before you start 53 | 54 | The history looks like this in the beginning: 55 | 56 | -----o <- special branch (current) 57 | / 58 | ---o <- common branch 59 | 60 | The 'special' branch has been tested for the feature you are 61 | working on, and this represents a stable point in the development 62 | to try and re-organise the code, separate out 'common' code from 63 | 'special' code, etc. 64 | 65 | Before you start, make a temporary branch TEMP from 66 | 'special'; leave special where it was. 67 | 68 | git checkout -b TEMP special 69 | 70 | You now make some changes for the special customer, which 71 | also involve some 'common' changes that need to be ported 72 | back to the common branch. The topology now looks like 73 | this, where A, B, C, are changes that logically belong on 74 | 'common', and 1, 2, 3, are changes that are specific to this 75 | customer. 76 | 77 | Notice that the 2 sets of changes are intermixed because 78 | that is how the development happened, and that there is even 79 | one commit where common and special changes are mixed 80 | (perhaps you realised this only later). 81 | 82 | -----o--A--B1--2--3--C <- "TEMP" branch (current) 83 | / 84 | ---o <- common 85 | 86 | Meanwhile, just to make things interesting, the common 87 | branch has also had some other, unrelated changes which you 88 | eventually want on the special branch as well. 89 | 90 | -----o--A--B1--2--3--C <- "TEMP" branch (current) 91 | / 92 | ---o--X--Y <- common 93 | 94 | ## Separating 'common' and 'special' 95 | 96 | The first thing to do is to tease the tangled commits apart 97 | using rebase. 98 | 99 | Using `git rebase -i special`, get the topology into this 100 | shape. Note that we have split the "B1" commit into B and 1 101 | separately. `git help rebase` has a very simple and clear 102 | section on splitting commits, so I will not detail that 103 | here. 104 | 105 | -----o--A--B--C--1--2--3 <- "TEMP" branch (current) 106 | / 107 | ---o--X--Y <- common 108 | 109 | At this point, the tree that results should be identical to the one you 110 | started this exercise with, so ideally there should be no need to test. You 111 | can, if you wish, check that the trees are indeed the same 112 | 113 | git diff TEMP@{1} TEMP 114 | 115 | The `@{1}` notation specifies the shape of the TEMP branch before the rebase 116 | started. 117 | 118 | ## Updating and testing the 'common' branch {#utcb} 119 | 120 | Now switch to the 'common' branch and cherry pick the 121 | changes that belong on 'common'. The simplest way to cherry 122 | pick is gitk. 123 | 124 | git checkout common 125 | gitk 126 | # and cherry pick first A, then B, then C, in order 127 | 128 | At this point, your TEMP branch has still not changed from when you started 129 | this re-organisation. However, you have now introduced 3 new commits onto 130 | the 'common' branch, so that set of changes needs to be tested to make sure 131 | things are fine. 132 | 133 | -----o--A--B--C--1--2--3 <- "TEMP" branch 134 | / 135 | ---o--X--Y--A'--B'--C' <- common (current) 136 | 137 | Be sure you test the new functionality before proceeding. This test will 138 | likely be different from your tests on the TEMP branch, because only part of 139 | the new code in TEMP goes to 'common'. If the test failed or required fixups, 140 | do them in the context of the 'common' case only, right here on the 'common' 141 | branch. **Note that this affects the rebase coming up later!** 142 | 143 | ## Merging 'common' into 'special' 144 | 145 | Once that test is done, merge from 'common' to 'special' 146 | 147 | git checkout special 148 | git merge common 149 | 150 | which results in the following topology: 151 | 152 | A--B--C--1--2--3 <- TEMP 153 | / 154 | ----o-----------------o <- special (current) 155 | / / 156 | ---o--X--Y--A'--B'--C' 157 | 158 | ## Fixing up 'special' 159 | 160 | Now all we need is to get commits 1, 2, and 3 onto 'special'. Although this 161 | is easiest done by using 'rebase', that will only work if your [updating and 162 | testing on 'common'](#utcb) did not cause any changes or fixups (that is, the 163 | changes A, B, and C are still identical to the changes A', B', and C'. 164 | 165 | In the general case, therefore, cherry-pick is better, as long as you make 166 | sure you don't miss any commits: 167 | 168 | gitk 169 | # and cherry pick first 1, then 2, then 3, in order 170 | 171 | This gives you the following topology (in which we have ignored the TEMP 172 | branch) 173 | 174 | 1'--2'--3' <- special (current) 175 | / 176 | ----o-----------------o 177 | / / 178 | ---o--X--Y--A'--B'--C' 179 | 180 | ## Final sanity check 181 | 182 | At this point you should *definitely* re-test all the changes you made, to 183 | make sure nothing got missed out. If there were no 'X' and 'Y' commits on 184 | the 'commits' branch, you could try 185 | 186 | git diff TEMP special 187 | 188 | to check that the tree is still the same as before. But again, in the 189 | general case, you probably will have commits 'X' and 'Y' included so it is 190 | necessary to re-test. 191 | 192 | Once all this is done, you don't need TEMP anymore, and can delete it: 193 | 194 | git branch -d TEMP 195 | -------------------------------------------------------------------------------- /archived/special-branches.mkd: -------------------------------------------------------------------------------- 1 | % customer branches 2 | 3 | 4 | 5 | Here's a question that someone asked (both question and response have been 6 | heavily edited): 7 | 8 | > Hello. I have a Ruby on Rails application. This is currently managed using 9 | > GIT. I have another business that wants a customised copy of this site. Is 10 | > it possible to use GIT to do this? 11 | 12 | > Currently I have one site in directory "custA". I want to make a copy in 13 | > "custB" which is a branch. They are the same base system with customer 14 | > specific modifications. How does this work? 15 | 16 | > For example, on custA, I make commits 1, 2, 3. In custB, only commits 1 17 | > and 3 are relevant. Is it possible to pull only specific commits across? 18 | > Would I be better served using a central repository and then using 19 | > different branches, one for each site? 20 | 21 | > What is the "best" way to do this using Git? 22 | 23 | There are several issues actually being raised here, so we'll look at them one 24 | at a time. 25 | 26 | ---- 27 | 28 | # SVN-itis 29 | 30 | The first thing to note is that the question reflects what I have started 31 | calling `SVN-itis` -- where "branch" and "(sub)directory" are conflated :-) 32 | 33 | Some [basic terminology](../terminology.html) is probably useful, if you're 34 | really new to git, or perhaps some info on [branches in 35 | git](branches.html), but neither of these quite manage a cure for 36 | SVN-itis. So let's lay it out: 37 | 38 | > In git, there is **no connection** between a branch and a subdirectory. 39 | Subdirectories are whatever your project needs them to be, and branch names 40 | are whatever you want them to be. You can have a branch whose name happens to 41 | be the same as that of one of your project directories, if you really need to. 42 | 43 | So "custA" is **not** a directory. Neither is "custB"; nor indeed any other 44 | branch. And if you have a directory called "include" or "src" or 45 | "Documentation", that does **not** become a branch in your repo! 46 | 47 | When you checkout a branch called "custA", your "working tree" is populated 48 | with the customer "A" specific version of your code. It's very likely that 49 | the actual directory structure for this version is pretty much the same as, 50 | say, for customer "B", and both of them are similar to the directory structure 51 | of the main branch. 52 | 53 | # cherry-pick versus merge 54 | 55 | [also see `git help workflows`] 56 | 57 | "*Is it possible to pull only specific commits across?*" 58 | 59 | Well certainly yes; this is called **cherry-picking**, and git can do that 60 | from the command line, or from the GUI. But it is **not** the right thing to 61 | do in this circumstance, or indeed many other similar ones. 62 | 63 | In terms of "history", a cherry-pick is the same as "take a diff of *that* 64 | commit versus it's parent, and apply that same change *here* in *this* branch, 65 | and commit". Git does not remember that you pulled this change in any way 66 | whatsoever, and does not associate these two commits (the one you picked, and 67 | the new one made here as a result) in any long term way to ease maintenance. 68 | [Experts: *patch-id* is not relevant here for this discussion so leave it 69 | alone ok? :-)] 70 | 71 | Secondly, if the feature you implemented was spread across more than one 72 | commit (as any non-trivial feature *should*!), you have to remember to 73 | cherry-pick *all* of them. In the *right order*! Miss one, or pick them in 74 | the wrong order, and things go bad. 75 | 76 | When you **merge** a branch, on the other hand, git remembers that you merged 77 | it. And since you only deal with the tip of the branch, not individual 78 | commits, it's git's job to make sure that they all come in, and in the right 79 | order. In particular, (as `git help workflows` says), 80 | 81 | ...a merge can carry over the changes from 1, 10, or 1000 commits with 82 | equal ease, which in turn means the workflow scales much better... 83 | 84 | So the long term way to do this is by merging. Just remember that when you 85 | merge a branch, *all* the changes in that branch are brought in (merging is 86 | *not* a selective operation) so it is best to *create a different branch for 87 | each logically separate set of changes*. 88 | 89 | # customer specific branches 90 | 91 | The idea is you use one common branch, and two (or as many as you need) 92 | customer specific branches. All common changes go into the master, and each 93 | customer branch gets changes that pertain only to that customer. Periodically 94 | (when master is considered to be at a stable point), you'll merge changes from 95 | master into the customer branch (`git checkout custA; git merge master`). 96 | This brings in newer "common" code into the customer branch. You will 97 | **never** merge the other way -- that would pollute master with 98 | customer-specific code. 99 | 100 | When you make a delivery to customer A, you checkout the "custA" branch and 101 | send that. And of course similarly for other customers. 102 | 103 | Now let's say you acquire a new customer, "C", and a bit later find a feature 104 | that customers A and C want, but B doesn't. You create (aka "fork") a branch 105 | off of master (`git checkout -b AC_feature master`), code/test it, making 106 | commits as you go, and then merge it into A and C (`git checkout A; git merge 107 | AC_feature` and similarly for customer C). You do **not** code it in A and 108 | then rely on merging A into C, because that would get all of A into C. 109 | 110 | If, sometime later, you find a minor bug in that feature, you make the change 111 | in the same branch (`git checkout AC_feature; edit/test/commit`), and then you 112 | merge it into `custA` and `custC` as above. 113 | 114 | # Summary 115 | 116 | The main thing we're avoiding in all this is cherry-picking specific commits 117 | because you only wanted a part of that code in this branch -- cherry-picking 118 | is certainly doable, but it is not scalable and in the long term it's a pain. 119 | 120 | Of course, you do have to be disciplined about which branch you make each 121 | commit in, in order to keep things properly separated. 122 | 123 | But [here](special-branch-fixups.html) is one way to fix up things if you did 124 | not manage to do that for some reason. 125 | -------------------------------------------------------------------------------- /archived/svn.mkd: -------------------------------------------------------------------------------- 1 | % for people who think SVN is good enough ;-) 2 | 3 | The official comparison is [here](http://git.or.cz/gitwiki/GitSvnComparsion). 4 | There is also a [Git - SVN crash course](http://git-scm.com/course/svn.html). 5 | 6 | *Lots of SVN info is scattered in a few other files in this directory; 7 | eventually it should all be pulled into this file.* 8 | 9 | ^^as Churchill said, so much to do, and so little time in which to do it... (*sigh*)^^ 10 | 11 | What follows is my understanding of the SVN scenario, from various sources. I 12 | personally have used SVN only briefly. If there are errors in the SVN part of 13 | this description please let [me](mailto:sitaramc@gmail.com) know. 14 | 15 | # briefly... 16 | 17 | Git's advantages over SVN (all of them affect productivity and/or 18 | maintainability, indicated in parens as **P** or **M**) are: 19 | 20 | * **(P)** handles merges automatically (in fact SVN doesn't really "handle" 21 | merges; merge history must be manually recorded and managed, and it's 22 | almost impossible to have 2 branches merging regularly in SVN without a 23 | lot of pain for the integration team) 24 | 25 | * **(M)** handles file renames correctly; helps in refactoring (in SVN, a 26 | rename is handled as a delete of the old file plus an add of the new file, 27 | and it is only tracked as such if you explicitly told svn about the 28 | rename. That is not the only brittle aspect; renames and merges don't mix 29 | well, apparently. Also, SVN may [become confused][wpsvn1] when files are 30 | modified and renamed in the same commit.) 31 | 32 | * **(P, M)** devs can create local branches without polluting the central server 33 | -- experimental features can be developed and tested "on the side", with 34 | full revision control and granular commits. If the experiment worked, you 35 | bring it into the main repo (without losing the individual commits), 36 | otherwise you toss it. In SVN, a successful side project is forced to 37 | enter the main project as one large chunk of code, which seriously affects 38 | future maintainability. 39 | 40 | * **(P, M)** devs make lots of small commits instead of one humongous commit -- 41 | much easier for code review, debugging, cherry-picking, and merging with 42 | other changes. Merge-conflict resolution happens on much smaller units 43 | instead of one huge chunk of code dumped on the repo! In SVN, every 44 | commit goes to the server, forcing commits to be large and monolithic, in 45 | turn causing every merge to be a serious exercise rather than a couple of 46 | minutes work. 47 | 48 | * **(P)** common VCS operations do not need network or server access, and are 49 | blazingly fast. SVN and other VCSs may take so long that a developer who 50 | is, say, trying to trace the changes that caused a bug may feel it's 51 | easier to go through the code himself than run a 'diff' against the last 52 | known good version! That is, these VCSs have the tools but it's a pain to 53 | use them! 54 | 55 | Git does a lot of things better than any other VCS: 56 | 57 | * **(P)** branching/merging is so bad in most other VCSs that lots of projects 58 | forgo all the advantages of parallel development! Or they have to have a 59 | separate "merge team", and they freeze development for a couple of days to 60 | do the merge. With git, merges (and therefore, merge conflicts, if any) 61 | are (i) handled by the developer closest to the merged code, not an 62 | upstream integrator who probably doesn't know the new code well, and (ii) 63 | processed in many small chunks instead of one large chunk of code. 64 | 65 | * **(M)** git doesn't track files, it tracks content. So if a piece of code 66 | moved from one source file to another, and you look at the history of that 67 | file visually, git will tell you that these lines came from that file over 68 | there, and it'll also tell you the history of those lines before they came 69 | here. This is way beyond what any other VCS can imagine doing, and is a 70 | real lifesaver for someone who picks up a complex project for maintenance 71 | or a new team member is trying to understand the existing project. 72 | 73 | # ...and a bit more detail 74 | 75 | ## 'svn update' on very active projects 76 | 77 | When you, as a developer, have made a fair number of changes on your 78 | workstation, and wish to commit these to the SVN repo, you do an 'svn update'. 79 | This brings in the latest changes from the server. 80 | 81 | Unfortunately, if the other developers have also been very active, there could 82 | be a lot of new/changed code. All of those changes, in one fell swoop, are 83 | now merged into your working copy, so conflicts are very likely. 84 | 85 | Worse, the 'svn update' has managed to lose the separation between your local 86 | changes and the updates that came from the server. You now have exactly one 87 | chance to resolve those conflicts and commit the result. And you'd better do 88 | it fast -- before the upstream tree changes *again*! 89 | 90 | [This is when an SVN newbie will realise he should have backed up his current 91 | source tree using tar or zip ;-)] 92 | 93 | With git, you would not do the `git pull` while you still have uncommitted 94 | changes in your local repository. This is a *distributed* VCS, so you have a 95 | local repository to take care of all that. 96 | 97 | So just commit all *your* changes locally, and *then* do a `git pull`! 98 | 99 | Of course this will have the same conflicts as in SVN and you still have to do 100 | a manual conflict resolution, *but*: 101 | 102 | 1. your local changes are *cleanly* saved, so if you botch up the manual 103 | conflict resolution, you can go back to your last local commit and try 104 | again. As many times as you need to, really. 105 | 2. if you do a `git pull --rebase`, (which is closer to what SVN does 106 | actually), then git will apply your local changes *one commit at a time* 107 | instead of the whole thing in one shot, making the conflict resolution 108 | also go in small, easily digestible chunks. 109 | 3. in rare cases, the 'upstream' has changed so much that a lot of your local 110 | changes become invalid and you have to redo them. With SVN -- you have to 111 | throw the whole lot away and start again. With git, you would have made a 112 | series of small, granular, commits on your local tree, and this lets you 113 | salvage the pieces that are still acceptable and redo only those that are 114 | not. Then you do your `git pull` or `git pull --rebase` again. 115 | 116 | ^^Basic idea from a post by Junio at 117 | ^^ 118 | 119 | ## local caching and repository size 120 | 121 | ### What extra information is cached locally? 122 | 123 | When you do an 'svn checkout', you get a working copy of the revision you 124 | checked out, plus svn saves away an extra copy of the same stuff. This allows 125 | you to do things like see what you changed with respect to the checked out 126 | version. 127 | 128 | But if you need a diff between your copy and some other version, you need 129 | network access. If you need a diff between two checked-in revisions, again 130 | you need network access. 131 | 132 | When you do a `git clone`, however, git stores the complete history of all the 133 | branches that the parent repository has! So the only time you now need 134 | network access is when you want to update the server, nothing else. 135 | 136 | This might make you think git's repositories are *huge*! Far from it; here's 137 | [an example](http://keithp.com/blogs/Repository_Formats_Matter/) that uses the 138 | Mozilla repository, with full history from 1998 or so: 139 | 140 | * CVS repo: 2.7 GB 141 | * imported to SVN: 8.2 GB 142 | * imported to GIT: 450 MB! 143 | * (a full checkout of just the source: 350 MB) 144 | 145 | That's a ratio of almost 20:1 in size over SVN. 146 | 147 | # some links 148 | 149 | * : 150 | the first example, 'Endless, Easy, Non-File-System-Based, Local Branches', 151 | is particularly powerful and convincing 152 | * from 153 | somewhere in the trenches 154 | * has 155 | something about changeset-atomic but not commit-atomic. 156 | 157 | ---- 158 | 159 | [wpsvn1]: http://en.wikipedia.org/wiki/Apache_Subversion#Current_limitations_and_problems 160 | -------------------------------------------------------------------------------- /archived/vss2git.mkd: -------------------------------------------------------------------------------- 1 | % converting Visual Source Shredder to GIT 2 | 3 | [Thanks to http://martinfowler.com/bliki/VersionControlTools.html for the 4 | new expansion of VSS] 5 | 6 | This is a 2 step process. For large values of 2, as they say :) But the nice 7 | thing is it can all be done in Linux; no need to use a Windows machine as long 8 | as you have a copy of the full VSS repo. 9 | 10 | # build vss2svn 11 | 12 | The base for all this is . What I 13 | did is the following: 14 | 15 | * download the latest vss2svn (this includes ssphys also): 16 | 17 | svn checkout http://svn.pumacode.org/repos/vss2svn/trunk/ vss2svn 18 | 19 | * follow all the instuctions to install all the various perl modules needed, 20 | copied [here](#perlmodinstalls) just in case. 21 | 22 | * install libboost-devel; ssphys needs it to build. On my current system 23 | (Mandriva 2009), the version was 1.36. I got a compile error which I 24 | fixed by running [this patch](#libboostpatch) (don't ask me how I found 25 | this -- I compared the nearest boost libraries with each other and 26 | determined that this only seemed to be a name change, and that too *only* 27 | in 1.36 -- very weird, but anyway...) 28 | 29 | * build and install vss2svn (again, instructions from the main site 30 | reproduced here for convenience): 31 | 32 | cd vss2svn 33 | perl Build.PL 34 | ./Build 35 | sudo ./Build install 36 | 37 | And that should be that... 38 | 39 | # run vss2svn 40 | 41 | This should be easy enough, for most normal repos. You need to get the entire 42 | VSS repo onto your system (the one that contains something called 43 | 'srcsafe.ini'). Put that in some "work" directory, and do this: 44 | 45 | vss2svn.pl --vssdir PATH_TO_VSS_REPO --revtimerange 60 46 | 47 | I have no idea how to deal with labels etc., properly in this command, but the 48 | basic stuff should work fine. 49 | 50 | # load the SVN dump file 51 | 52 | The previous step should produce just an SVN dump file, which you need to 53 | load, and that gives you an SVN repo. 54 | 55 | svnadmin create svnrepo 56 | svnadmin load svnrepo < SVN_DUMPFILE 57 | 58 | You may want to checkout this repo and at least see what "projects" it has, 59 | because I do not know any other way of doing this if you don't already know 60 | (from the VSS side). 61 | 62 | mkdir svnco 63 | svn checkout file://$PWD/svnrepo svnco 64 | 65 | # convert svn to git 66 | 67 | This is, naturally, the easiest of all, especially if you don't intend to go 68 | back :) 69 | 70 | mkdir gitrepo 71 | cd gitrepo 72 | git svn clone file://PATH_TO_SVN_REPO 73 | 74 | Of course, if you have used the VSS repo to store multiple projects, this will 75 | not work right -- VSS/SVN can happpily dump unrelated projects in one 76 | repository (or subdirectories masquerading as projects for that matter), 77 | whereas in git each project is in its own repository. 78 | 79 | So do it this way: 80 | 81 | git svn clone file://PATH_TO_SVN_REPO/projectname 82 | # for each project 83 | 84 | # checking the results 85 | 86 | ## tags 87 | 88 | Tags (labels in VSS) don't seem to carry across properly. 89 | 90 | ^^[rant] My idea of a tag is a symbolic name for a certain revision, so if you 91 | check it out you should see approximately the same number of files that the 92 | repo had around that time frame. What I actually see is that the number of 93 | files representing the various tags (as seen from an SVN checkout) range from 94 | 5% to 75% of the actual number of files in the repo! So -- until I see a VSS 95 | repo where the tags are actually used (and I mean *used*, as in, "these tags 96 | do get *checked out* when needed; they're not just for show!") I'm not going 97 | to worry about it.^^ 98 | 99 | ## deleted files 100 | 101 | I've also not tested if renamed/deleted files etc also work OK, but I think 102 | they ought to. 103 | 104 | ## that damn CRLF thing 105 | 106 | When you do it this way, you don't have an opportunity to fix the CRLFs as 107 | they go in -- they'll all go into the repo as CRLF. If you try to force it on 108 | the "git svn clone" itself (by prepping a blank git repo with `git config 109 | core.autocrlf input` and then svn-cloning into that), you get checksum errors! 110 | 111 | You have to do this after the fact. Here's the sequence: 112 | 113 | git config --unset core.autocrlf 114 | git checkout branch 115 | git config core.autocrlf input 116 | git filter-branch --tree-filter 'find . -type f -print0|xargs -0 touch' HEAD 117 | git config --unset core.autocrlf 118 | 119 | The first 'unset' is just a precaution. If you do a checkout with autocrlf 120 | set to input, the work tree will immediately look dirty, so the filter-branch 121 | will refuse to run. So you checkout under "default" conditions, then set the 122 | autocrlf config, then run the tree filter. 123 | 124 | The last 'unset' is required; you really don't want autocrlf to be anything on 125 | a Unix box. 126 | 127 | Note: in theory, a dummy filter that does nothing *should* work. But it seems 128 | to miss a lot of files, which still go in with CRLFs. Doing an explicit touch 129 | seems to be the only way. I have no idea why this is so. 130 | 131 | ## bottom line 132 | 133 | Anyway, your bottom line should be: 134 | 135 | 1. *confirm that the tip is OK*: make sure that the actual trees generated at 136 | the tip of the git repository match those in a fresh "get" from the 137 | corresponding project in VSS 138 | 2. *try to confirm past history is OK*: if possible, make the same check for 139 | a couple of intermediate revisions also 140 | 3. *save the VSS repo* in a read-only location for future reference, should 141 | there ever (much later in time) be a question on the accuracy of the 142 | history at some revision that was not explicitly checked during the 143 | migration. 144 | 145 | # alternative method using perl on windows 146 | 147 | There is another method, achieved by hacking a perl script that was supposed 148 | to convert [to SVN](http://www.riseup.com/~brettw/dev/VSS2Subversion.html), to 149 | make it go [to git](../tools/vss2git.pl) instead. Pros and cons: 150 | 151 | * (+) no CRLF problem 152 | * (+) easier to use: you just need msysgit and this program, no messing 153 | around with all these dependencies for vss2svn (but then, you can execute 154 | vss2svn the same way too -- they have a standalone windows executable) 155 | * (-) **NOT** very reliable; please double check your data if you really 156 | care about history. Deep down beyond a point where some files were 157 | deleted, I found mismatches with a VSS "get" directory. 158 | * (-) leaves vssver.scc and other junk lying around 159 | * (-) definitely can't handle deletes 160 | * (-) timestamps only to the nearest minute 161 | 162 | One reason why I'm keeping this around is if a VSS repo is corrupt enough (and 163 | it seems that happens quite often) then maybe only the original VSS can read 164 | it. To recover usable data from such an instance may be a futile attempt but 165 | no harm keeping two tools around...! 166 | 167 | ---- 168 | 169 | # Appendices 170 | 171 | 172 | 173 | ## installing the perl modules {#perlmodinstalls} 174 | 175 | Note: I *did* indeed have to install DBD::SQLite2 manually. Also, Text::Glob 176 | had to be installed using `perl -MCPAN -e shell` followed by `install 177 | Text::Glob`; for some reason the "-e install ..." thing didn't work 178 | 179 | for m in Module::Build XML::Simple Time::CTime DBD::SQLite2 DBI Tie::IxHash Text::Glob Data::UUID; do 180 | perl -MCPAN -e "install $m" 181 | done 182 | 183 | # SQLite2 failed to install, even with "force install ...", so: 184 | cd ~/.cpan/build/DBD-SQLite2-0.33 185 | # May need to create the makefile... 186 | # perl Makefile.PL 187 | make install 188 | 189 | # the Config:Ini module is not in CPAN, so: 190 | wget http://backpan.perl.org/authors/id/A/AV/AVATAR/Config-Ini-1.08.tar.gz 191 | tar xzf Config-Ini-1.08.tar.gz 192 | cd Config-Ini-1.08 193 | perl Makefile.PL 194 | make 195 | make install 196 | 197 | ## patch for libboost 1.36 {#libboostpatch} 198 | 199 | commit 4a3a283593bf8a991e0553e3ac3252c75a1349db 200 | Author: Sitaram Chamarty 201 | Date: Thu Apr 16 09:27:00 2009 +0530 202 | 203 | (touch wood) fixed up a weird incompatibility with my *specific* version of boost 204 | 205 | diff --git a/vss2svn/ssphys/SSPhysLib/SSItemInfoObject.cpp b/vss2svn/ssphys/SSPhysLib/SSItemInfoObject.cpp 206 | index 7d88a8e..0cd12ea 100644 207 | --- a/vss2svn/ssphys/SSPhysLib/SSItemInfoObject.cpp 208 | +++ b/vss2svn/ssphys/SSPhysLib/SSItemInfoObject.cpp 209 | @@ -162,7 +162,7 @@ std::string SSItemInfoObject::GetDataFileName () const 210 | std::string fileName = GetFile ()->GetFileName () + GetLatestExt (); 211 | boost::filesystem::path fpath(fileName, boost::filesystem::native); 212 | 213 | - if (!boost::filesystem::exists(fpath) && fpath.has_leaf() && fpath.has_branch_path()) 214 | + if (!boost::filesystem::exists(fpath) && fpath.has_filename() && fpath.has_parent_path()) 215 | { 216 | std::string lcLeaf = fpath.leaf(); 217 | std::string ucLeaf = fpath.leaf(); 218 | 219 | 220 | -------------------------------------------------------------------------------- /archived/whitespace-index-filter.mkd: -------------------------------------------------------------------------------- 1 | % fixup whitespace errors 2 | 3 | When you have whitespace errors in a repo and want to fix them all together, 4 | here's what you do. Written by doener circa 2009-07-12 19:23 5 | 6 | So let's say the following code is in `~/git-scripts/ws-fix.sh` 7 | 8 | #!/bin/bash 9 | 10 | # from doener (who else!) 11 | # to be called as an index-filter 12 | 13 | if git rev-parse --quiet --verify $GIT_COMMIT^ >/dev/null 14 | then 15 | against=$(map $(git rev-parse $GIT_COMMIT^)) 16 | git reset -q $against -- . 17 | else 18 | # Initial commit: diff against an empty tree object 19 | against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 20 | git rm --cached -rfq --ignore-unmatch '*' 21 | fi 22 | 23 | git diff --full-index $against $GIT_COMMIT | git apply --cached --whitespace=fix 24 | 25 | Notes: 26 | 27 | * the `map` translates the original sha1 to the sha1 of the rewritten 28 | commit. The diff needs to go against the rewritten one, so that the patch 29 | applies without conflicts/fuzz. 30 | 31 | * run this like: `git filter-branch --index-filter '. ~/git-scripts/ws-fix.sh'` 32 | 33 | * a pictorial representation of what this script does each time it is 34 | called (also from doener a few minutes later when I still couldn't get 35 | it!): 36 | 37 | Original: 38 | 39 | A---B---C---D---E 40 | 41 | Rewritten so far: (1 == rewritten A, and so on) 42 | 43 | 1---2---3 44 | 45 | To create 4 we do: 46 | 47 | map D^ == map C == 3 48 | 49 | so: git diff 3 D | git apply .... 50 | 51 | Other possibilities: 52 | 53 | If the whitespace problem causing conflicts is something like indentation 54 | shift, etc., and is not amenable to `git apply --whitespace=fix`, the 55 | following may work. We assume the "remote" version is the one with the 56 | unnecessary indentation changes: 57 | 58 | git show :1:filename > filename 59 | git diff -b :1:filename :3:filename | git apply 60 | # (might need munging; the diff header has :1: and :3: in it...) 61 | git merge-one-file :1:filename :2:filename $(git hash-object -w filename) filename 62 | -------------------------------------------------------------------------------- /archived/workflow-integ-devs.mkd: -------------------------------------------------------------------------------- 1 | % dev/integ workflow 2 | 3 | # workflow 4 | 5 | This is one possible workflow for dev/integ using gitolite. It assumes that 6 | there is one "integrator" and N developers "dev1", ... "devN". 7 | 8 | ## branches 9 | 10 | * `integ` -- a branch that is `R` (readonly) for devs, `RW+` for integrator. 11 | This branch will always be kept in a compilable, basically runnable, state 12 | by the integrator. The history of this branch will be kept reasonably 13 | clean. 14 | 15 | Each developer will start a new piece of work or task using `integ` as a 16 | starting point, and making sure that when he submits his work it builds 17 | upon this stable point. 18 | 19 | * `dev/dev1/`, `dev/dev2/`, ... `dev/devN/` 20 | 21 | branches under the `dev/devX/` hierarchy belong to the developer called 22 | `devX`. He submits his work to the integrator by pushing to one such 23 | branch and emailing the integrator the branch name (say 24 | `dev/sitaram/issue3423` or `dev/someone-else/bugfix-2321`. 25 | 26 | * master -- a branch that is even more sacred than `integ`. Its usage and 27 | role are optional in the below described flow, but it can be used to 28 | filter `integ` even more, maybe based on some EQA (External Quality 29 | Assurance) perhaps. If so, its name can be changed to reflect that. 30 | 31 | ## assumptions / startup: 32 | 33 | * a repo is created 34 | * the code is kept in a branch called `integ`, even if it is bare minimum 35 | code in the beginning 36 | 37 | ## developer workflow 38 | 39 | We use a sample developer called dev5 in the examples below. 40 | 41 | dev5 gets some work/spec/issue to work on. He is given, or chooses, a short 42 | name for the work he is doing. Examples: 43 | 44 | xyz-module-error-23 45 | bugfix-2321 46 | issue-3394 47 | add-vorbis-support 48 | 49 | In the rest of this example we will use `issue-3394` 50 | 51 | * dev clones the repo, if not already cloned 52 | 53 | git clone [...] 54 | 55 | * fetch and checkout the current `integ` branch, making the new `issue-3394` 56 | branch from it 57 | 58 | git fetch origin 59 | git checkout -b issue-3394 origin/integ 60 | 61 | ---o---o---I 62 | (o, o = previous commits, irrelevant to us) 63 | I = origin/integ = issue-3394 64 | (current branch is issue-3394) 65 | 66 | * (**LOOP POINT**) work on this branch 67 | 68 | git checkout issue-3394 69 | # (edit/compile/test) 70 | git add, git commit 71 | # repeat as needed 72 | # the last step should be a "test", ideally 73 | 74 | ---o---o---I---a---b---c---d 75 | I = origin/integ 76 | a,b,c = intermediate commits 77 | d = issue-3394 78 | (current branch is issue-3394) 79 | 80 | now he's ready to send. In the meantime, `integ` may have moved ahead, and he 81 | has to make it work against that: 82 | 83 | * fetch integ again and rebase 84 | 85 | git fetch origin 86 | 87 | ---o---o---I---J---K 88 | K = origin/integ now 89 | 90 | git checkout issue-3394 # if not already done 91 | git rebase origin/integ 92 | 93 | what does this rebase do? It takes this: 94 | 95 | ---o---o---I---J---K 96 | \ 97 | \ 98 | a---b---c---d 99 | 100 | and moves the "a, b, c, d" on top of K: 101 | 102 | ---o---o---I---J---K---a'---b'---c'---d' 103 | (a',b',c',d' are rebased versions of a,b,c,d) 104 | (K = origin/integ, d' = issue-3394) 105 | 106 | There is a reason for doing it this way. Dev5 is the one who knows the 107 | new code best, and he should be integrating it with the latest version of 108 | `integ` at any time he submits. And since `issue-3394` is a private 109 | branch, he can rebase it as often as he likes. 110 | 111 | [SIDE NOTE] why do we use rebase instead of merge here? 112 | 113 | **this is not a hard and fast rule -- you can use merge if you like. Feel 114 | free to experiment and see what works best for your team, because a lot 115 | also depends on their level of comfort with the process** 116 | 117 | However, in my opinion, work that has not been pushed out *and* accepted 118 | upstream should ideally be rebased against new upstream. The main 119 | difference is that, if the *acceptance* of the work goes through a few 120 | iterations (let's say it is rejected and partially redone 2-3 times), 121 | using rebases is easier to do, and also will result in a cleaner looking 122 | *final* commit list. 123 | 124 | * retest one more time, to make sure the new `J` and `K` commits have not 125 | caused a problem for `issue-3394` 126 | 127 | if the test fails, he has to fix his commits (a', b', c', d') or add some 128 | new commits (maybe e, f) and make it work. 129 | 130 | * when test OK, push `issue-3394` under your own hierarchy (each time he 131 | comes back to "LOOP POINT" because something was rejected by code review 132 | or integ testing, the `v1` will increase -- `v2`, `v3`, etc) 133 | 134 | git push origin issue-3394:dev/dev5/issue-3394/v1 135 | 136 | * send email to integrator asking him to pull and test 137 | `dev/dev5/issue-3394/v1` 138 | 139 | ## integrator 140 | 141 | * receive mail from dev5 saying `issue-3394` is done and ready 142 | 143 | * clone repo if not already done 144 | 145 | * fetch, make a test branch for testing `issue-3394` 146 | 147 | git fetch origin 148 | git checkout -b test_issue-3394 origin/dev/dev5/issue-3394 149 | 150 | * test, or do whatever he wants to do initially (maybe code review). If he 151 | doesn't like it, send it back for more work. **dev5 then restarts his 152 | process from the point marked "LOOP POINT" in his workflow above** 153 | 154 | * if it is OK so far, **test merge** it with the current *integ* branch. 155 | Ideally, this should be a **fast forward**, because dev5 *already* did 156 | this. 157 | 158 | git checkout -b test_integ_issue-3394 integ 159 | git merge origin/dev/dev5/issue-3394 160 | # this should be a fast forward, ideally 161 | # make some final tests 162 | 163 | If something went wrong, no problem; just delete the test branch and email 164 | dev5 saying what the problems are. For dev5, work again starts at "LOOP 165 | POINT" 166 | 167 | git branch -D test_integ_issue-3394 168 | 169 | However, if the tests were all ok, move integ forward and delete test 170 | merge branch 171 | 172 | git checkout integ 173 | git merge origin/dev/dev5/issue-3394 174 | git branch -D test_integ_issue-3394 175 | 176 | This issue (3394) is now closed, unless there is a regression later. It 177 | has been integrated successfully, and dev5 can be assigned some other 178 | task. 179 | 180 | # gitolite advanced features supporing this flow 181 | 182 | Here's a typical gitolite conf file: 183 | 184 | @myteam = dev1 dev2 ... devN 185 | 186 | repo myrepo 187 | RW+ = integrator 188 | RW+ dev/USER/ = @myteam 189 | 190 | That's it? How does, say `dev5` (assuming he is a member of `@myteam`), get 191 | access to write to `dev/dev5/something`? 192 | 193 | That is a unique feature of gitolite :-) When a rule has the string `/USER/` 194 | in the "refex" (see gitolite documentation for details), it replaces it with 195 | the name of the user invoking the push. This is effectively the same as 196 | manually adding one line like this 197 | 198 | RW+ dev/sitaram/ = sitaram 199 | 200 | for each member of `@myteam`. 201 | -------------------------------------------------------------------------------- /articles/articles.mkd: -------------------------------------------------------------------------------- 1 | % articles and write-ups 2 | 3 | These are some longer write-ups on git that I think are still useful. (If 4 | they weren't, they'd be dumped into the [archived](archived/index.html) 5 | directory!) 6 | 7 | * git as a [deployment](deploy.html) tool 8 | * [try it and see!](tias.html) -- a very popular article that shows you how 9 | easy it is to try pretty much *any* git feature safely and easily on your 10 | own userid 11 | 12 | * I've never seen *any* documentation for [gitk](gitk.html) anywhere so here 13 | it is! 14 | 15 | * [sizing a server](server-sizing.html) for git 16 | * [git performance](git-performance.html) 17 | 18 | * some nuances of [git blame](blame-detection-and-C-levels.html) 19 | * an older explanation of the [detached HEAD](detached-head.html). Still 20 | useful, but largely supplanted by the much more comprehensive -- and 21 | pictorial -- [git concepts simplified](gcs.html) 22 | * using git [over an HTTP proxy](git-over-proxy.html) 23 | * what does [git pull --rebase](git-pull--rebase.html) do? 24 | * rules for [git ignore](ignore-rules.html) explained a little better 25 | * what is a [reflog](reflog.html) and why is it useful? 26 | * why the [index/staging area](uses-of-index.html) is useful 27 | 28 | * good [version control habits](vc-habits.html) 29 | -------------------------------------------------------------------------------- /articles/blame-detection-and-C-levels.mkd: -------------------------------------------------------------------------------- 1 | % blame detection 2 | 3 | Git tracks content, not files. As a result, the `git blame` and the 4 | `git gui blame` commands can detect code moved or copied from elsewhere in 5 | the project. It's a very powerful feature, accessed by specifying the 6 | `-C` flag one or more times, but there are some nuances. 7 | 8 | # move detection versus copy detection {-} 9 | 10 | When the `-C` flag is given only once, it looks for code blocks that were 11 | **moved**. That is, it searches for new code among other files that were also 12 | modified in the same commit. This runs very fast. 13 | 14 | When you give the flag **twice**, it looks for new code among **all** the 15 | files in the parent commit, and so it detects code that was **copied**. 16 | 17 | `git gui blame` behaves like `-C -C` by default, but can behave like `-C` if 18 | `gui.fastcopyblame` is true. (In addition, it also appears to set `-w`, to 19 | ignore whitespace changes while blaming). 20 | 21 | # threshold, and how to specify it {-} 22 | 23 | There is a concept of a "threshold", which is the minimum number of 24 | alphanumeric characters required to count something as a code move/copy -- be 25 | sure to read under `-C` in `man git-blame`. 26 | 27 | This threshold defaults to 40 characters for copy detection, and 20 for move 28 | detection. You can override it by appending a number to the `-C` option. 29 | 30 | `git gui blame` defaults to 40 for this -- it actually sets `-C40` and calls 31 | (I assume) the command line blame tool. If you want to override it, use the 32 | GUI (Edit->Options), or directly set the `gui.copyblamethreshold` config 33 | variable. 34 | 35 | # documentation lacunae {-} 36 | 37 | The documentation does not seem to be very clear about the effect of _three_ 38 | `-C` options on `git blame`. (In the GUI this is done by choosing full copy 39 | detection from the right click menu). 40 | 41 | The best hint is in `builtin-blame.c`, which says, within a function called 42 | `blame_copy_callback`: 43 | 44 | /* 45 | * -C enables copy from removed files; 46 | * -C -C enables copy from existing files, but only 47 | * when blaming a new file; 48 | * -C -C -C enables copy from existing files for 49 | * everybody 50 | */ 51 | 52 | Sidenote: correlating the single and double cases in the code with the 53 | documentation, I imagine "removed files" actually means "code from some other 54 | modified file in the same commit", and similarly "existing files" means "code 55 | from any files in the parent commit". 56 | 57 | # my observations {-} 58 | 59 | * a very high threshold makes it behave like no `-C` flags were supplied 60 | -------------------------------------------------------------------------------- /articles/git-over-proxy.mkd: -------------------------------------------------------------------------------- 1 | 2 | 3 | % How to use git over an HTTP proxy, with socat 4 | 5 | Corporate firewalls and proxy typically block both of these (and often a lot 6 | more); here's how to get around them. 7 | 8 | If you're tracking a public repo, you will need to use the "git" protocol, 9 | because the "http" protocol is not very efficient, and/or requires some 10 | special handling on the server side. If you're pushing code to a public repo, 11 | you **definitely** need to use the "ssh" protocol. 12 | 13 | # a word about socat {-} 14 | 15 | I will be using "socat", an absolute corker of a program that does so many 16 | things it's incredible! Other people use corkscrew, ssh-https-tunnel, etc., 17 | which are all specialised for just one purpose. I prefer socat, and once you 18 | spend the 2-3 years :-) needed to read the man page, you will see why! 19 | 20 | The basic idea is that you will somehow invoke socat, which will negotiate 21 | with the HTTP(S) proxy server using the CONNECT method to get you a clean pipe 22 | to the server on the far side. 23 | 24 | However, do note that socat does have one disadvantage: the passwords to your 25 | proxy server are visible in to local users running `ps -ef` or something. 26 | I don't care since I don't have anyone else logging into my desktop, and the 27 | ability to use a program I already have anyway (socat) is more important. 28 | 29 | # proxying the **git** protocol {-} 30 | 31 | When I want to download a public repo, I just type 32 | 33 | proxied_git clone ...repo... 34 | proxied_git pull 35 | 36 | and so on, instead of 37 | 38 | git clone ...repo... 39 | git pull 40 | 41 | Here's the how and why of it. 42 | 43 | To proxy the git protocol, you need to export an environment variable 44 | called `GIT_PROXY_COMMAND`, which contains the command that is to be 45 | invoked. I have a shell function in my `.bashrc` that looks like 46 | this: 47 | 48 | proxied_git () 49 | ( 50 | export GIT_PROXY_COMMAND=/tmp/gitproxy; 51 | 52 | cat > $GIT_PROXY_COMMAND <) 96 | * create a file (eg., ~/.ssh/myauth) and put your http proxy 97 | username and password as "username:password" in it and save 98 | it. 99 | * safeguard the file 100 | 101 | chmod 600 ~/.ssh/myauth 102 | 103 | * open ~/.ssh/config and add the following entry, adding an explicit path to 104 | corkscrew if needed. 105 | 106 | host gh 107 | user git 108 | hostname github.com 109 | port 22 110 | proxycommand corkscrew your.proxy.ip 3128 %h %p ~/.ssh/myauth 111 | 112 | ## extra coolness for github {-} 113 | 114 | Noting that many corporate firewalls block access to the CONNECT method on 115 | ports other than 443, the good folks at github have an ssh server listening on 116 | 443 if you use the host "ssh.github.com", so you can replace the hostname and 117 | the port in the above ssh config stanza as appropriate, and you're all set 118 | -------------------------------------------------------------------------------- /articles/git-performance.mkd: -------------------------------------------------------------------------------- 1 | % git performance 2 | 3 | One of the things git did was to try and optimise disk storage by adopting an 4 | aggressive delta compression technique. Most version control systems give you 5 | this, but they only do deltas for **consecutive versions of the same file**. 6 | Git not only tries to optimise across non-adjacent versions of a file (like if 7 | you removed a huge bunch of lines, and then added them back again), it also 8 | leverages similarities with **other** files. 9 | 10 | The reason it does this is that it really tracks content, not just filenames. 11 | 12 | Anyway, all this means that a packed git repo is much, much, smaller than a 13 | repo in any other VCS. (The Mozilla tree sizes, at one time, were: 14 | 15 | One full checkout : 350 MB 16 | CVS repo : 2.7 GB 17 | SVN repo : 8.2 GB 18 | git repo : 450 MB 19 | 20 | Read that again: the entire history of Mozilla in barely a third more space 21 | than a normal checkout! 22 | 23 | So what does all this have to do with performance? Well, although all this 24 | was done purely for disk space reasons, it turned out to have a surprising 25 | effect on performance. 26 | 27 | It turned out (and in hindsight this was obvious) that, since the disk was the 28 | slowest component, keeping a small amount on the disk and making the CPU grunt 29 | a little was far, far, faster than not doing all this compression. 30 | 31 | In fact, people found that a git checkout is faster than a "cp -a", simply 32 | because of this tradeoff. Until you get used to it, this is a little 33 | mind-blowing. 34 | 35 | Anyway the bottom line is, performance is not an issue. 36 | -------------------------------------------------------------------------------- /articles/git-pull--rebase.mkd: -------------------------------------------------------------------------------- 1 | % what does "git pull --rebase" do? 2 | 3 | [To understand this article you need to understand what a reflog is, and what 4 | a rebase does, especially the full form of the rebase command] 5 | 6 | [My initial article was a little simplistic; more exact details added thanks 7 | to doener!] 8 | 9 | ---- 10 | 11 | Sometimes we have an upstream that rebased/rewound a branch we're depending 12 | on. This can be a big problem -- causing messy conflicts for us if we're 13 | downstream. 14 | 15 | Without going into why they would do that, and how many beers (I prefer 16 | rum+coke, thank you!) should be offered in compensation to downstream users, 17 | let's just try and describe how git helps you deal with it. 18 | 19 | The magic is `git pull --rebase`. 20 | 21 | A normal `git pull` is, loosely speaking, something like this (we'll use a 22 | remote called `origin` and a branch called `foo` in all these examples): 23 | 24 | # assume current checked out branch is "foo" 25 | git fetch origin 26 | git merge origin/foo 27 | 28 | At first glance, you might think that a `git pull --rebase` does just this: 29 | 30 | git fetch origin 31 | git rebase origin/foo 32 | 33 | But that will not help if the upstream rebase involved any "squashing" 34 | (meaning that the `patch-id`s of the commits changed, not just their order). 35 | 36 | Which means `git pull --rebase` has to do a little bit more than that. Here's 37 | an explanation of what it does and how. 38 | 39 | Let's say your starting point is this: 40 | 41 | a---b---c---d---e (origin/foo) (also your local "foo") 42 | 43 | Time passes, and you have made some commits on top of your own "foo": 44 | 45 | a---b---c---d---e---p---q---r (foo) 46 | 47 | Meanwhile, in a fit of anti-social rage, the upstream maintainer has not only 48 | rebased his "foo", he even used a squash or two. His commit chain now looks 49 | like this: 50 | 51 | a---b+c---d+e---f (origin/foo) 52 | 53 | A `git pull` at this point would result in chaos. Even a `git fetch; git 54 | rebase origin/foo` would not cut it, because commits "b" and "c" on one side, 55 | and commit "b+c" on the other, would conflict. (And similarly with d, e, and 56 | d+e). 57 | 58 | What `git pull --rebase` does, in this case, is: 59 | 60 | git fetch origin 61 | git rebase --onto origin/foo e foo 62 | 63 | This gives you: 64 | 65 | a---b+c---d+e---f---p---q---r (foo) 66 | 67 | You may still get conflicts, but they will be genuine conflicts (between p/q/r 68 | and a/b+c/d+e/f), and not conflicts caused by b/c conflicting with b+c, etc. 69 | 70 | ---- 71 | 72 | So how does this actually work? 73 | 74 | The command tries to find out which commits are *really* your local ones, and 75 | which had come from upstream in an earlier fetch. 76 | 77 | To do this, it looks at the reflog of the remote tracking branch 78 | (`origin/foo`, in this case). This reflog represents the tips of successive 79 | `git fetch` operations on `origin`, in "most recent first" order. 80 | 81 | For each reflog entry, (`origin/foo@{1}`, then `...{2}`, and so on) it checks 82 | if that commit is an ancestor of the current branch head `foo`. As soon as it 83 | finds one, it picks it as the starting point for the rebase (`e` in the 84 | example above). 85 | 86 | That might sound a little complicated, but it works out fine. Just try it 87 | next time your upstream rebases something on you. 88 | -------------------------------------------------------------------------------- /articles/gitk.mkd: -------------------------------------------------------------------------------- 1 | 2 | 3 | % the missing gitk documentation 4 | 5 | `gitk` is a very powerful GUI tool. It's one of those rare beasts where the 6 | pretty stuff is not just a crutch for the command-line-ignorant -- it actually 7 | does really useful things that just cannot be done in a CLI. 8 | 9 | Sadly, it is woefully undocumented. Scratch that, it's almost *completely* 10 | undocumented. 11 | 12 | [Update 2020-06-28: I just found [Exploring 13 | gitk](https://www.youtube.com/watch?v=BuDYATyhl0U), which is pretty neat too. 14 | A lot of things in gitk are better explained in video than text so be sure to 15 | check that out also.] 16 | 17 | This is my attempt to do something about that. Strictly speaking, you can 18 | explore the UI and find all these features yourself, and indeed, if you find 19 | any that are not listed here, please [email me](mailto:sitaramc@gmail.com). 20 | 21 | # colors and bold 22 | 23 | * local branch names are in a green background 24 | * remote branch names are in a mixed orange/green background 25 | * the currently checked out branch name is in bold 26 | * tags are on a yellow background 27 | * a yellow dot marks the current HEAD 28 | * a yellow square marks commits which have "notes" ('man git-notes' for what 29 | that means) 30 | 31 | # repository operations 32 | 33 | All these are from the commit list (the top pane): 34 | 35 | * right clicking on a commit message 36 | * create a tag 37 | * create a new branch 38 | * reset the current branch to this commit (soft/mixed/hard) 39 | * cherry-pick this current onto the current branch 40 | 41 | * right clicking on a branch name 42 | * checkout the branch (please heed the warning above 43 | * remove the branch 44 | 45 | # the main menu 46 | 47 | * reload: if you're doing stuff on the command line in another screen, and 48 | want those changes reflected in gitk, hit `F5`. 49 | 50 | `F5` updates the refs and shows you their new values *while still showing 51 | you the old ones*. It is most useful after operations like rebase, 52 | because you can compare the previous branch head with the new one. 53 | 54 | (`Shift-F5`, on the other hand, is a total refresh, throwing away 55 | everything that was previously shown.) 56 | 57 | * list references: to quickly go to a particular reference, hit `F2`. 58 | If there are too many, you can specify a glob pattern in the box at the 59 | bottom to subset the list. Clicking on a reference jumps to that 60 | reference. 61 | 62 | # browsing the commit list (top pane) 63 | 64 | Many of these functions also have character key bindings. For example "n" 65 | acts the same as a "down arrow". I'm not listing those; if you need them, 66 | look in the source code for a series of `bindkey` statements and match them up 67 | with the others. It's not hard, and you don't need to know Tcl. (I don't). 68 | 69 | * up/down arrow keys, pageup/down: obvious 70 | * left/right arrow keys: previous/next commit in browse history (think web 71 | browser's back/forward) 72 | * shift-up/down: find previous/next match (see [searching for commits](#sfc) 73 | below) 74 | 75 | # browsing the diff 76 | 77 | At any time, the bottom left pane shows a "diff", usually of the current 78 | commit shown in the top pane. The bottom right pane (by default) shows a list 79 | of files in this "diff". 80 | 81 | 82 | 83 | * spacebar: move forward 1 page in the diff view 84 | * backspace/delete: ditto, but backward 85 | * "f": move to next file in the diff. Both the bottom left and right panes 86 | will show a change when you do this. 87 | * "b": ditto, but previous file 88 | * click a file in the bottom right pane: scrolls the left pane to show that 89 | file's changes 90 | 91 | ## running a diff between two arbitrary commits 92 | 93 | * left click on the "new" commit 94 | * navigate using the scrollbar (no keyboard shortcut, AFAICT) to some other 95 | commit 96 | * *right-click* and choose "Diff this -> selected" 97 | 98 | Now you can browse that diff using the keyboard or mouse. Note that any 99 | movement that selects a different commit (like pressing an arrow key) will 100 | change the view to show that commit, so while examining this "diff", stick to 101 | [these keys](#bcpc). 102 | 103 | 104 | 105 | # searching for commits 106 | 107 | Searching for commits is done by typing something in the search box just below 108 | the SHA ID. (The "Search" box on the *next* line is to search for text within 109 | a commit diff; that's not the one we want, despite its name!) 110 | 111 | Here're some ways to search for commits. The commits that result will become 112 | highlighted in bold, so you can see them in the context of their surrounding 113 | changes. You can navigate between matches using the shift-up/down-arrow keys. 114 | 115 | There is a widget to the left of the search box that controls what type of 116 | search you do. By default it is set to "containing:", which searches the 117 | commit message. 118 | 119 | * searching on commit message: just hit `"/"` and type in any text. This 120 | will match all commits where the commit message contained the text you 121 | typed. 122 | 123 | * searching by filename: navigate to some commit that affected the file. 124 | Right click the filename in the bottom right pane and choose "Highlight 125 | this only". If you want to add more files to the search in an "OR" type 126 | match, right click some other file (doesn't have to be the same commit), 127 | and choose "Highlight this too". 128 | 129 | Notice that when you do this, the search type widget changes from 130 | "containing:" to "touching paths:". 131 | 132 | * searching by changed text: set the search type widget to "adding/removing 133 | string:", then type in a search text. 134 | 135 | Now that you've understood that widget, take a look at the others on the right 136 | also; they're fairly self-explanatory. Note that the last widget (All fields, 137 | Headlines, Comments, Author, Committer) is only valid when the type of search 138 | widget shows "containing:". 139 | 140 | # navigating the commit tree 141 | 142 | There are several ways to navigate the tree quickly. 143 | 144 | * the diff pane always shows all the parents and children of the current 145 | commit. Click on any of the hashes to go there. Some of the text from 146 | the commit message of those hashes is also shown, to give you an idea of 147 | what that is. 148 | 149 | * the diff pane also shows all the branches to which this commit belongs. 150 | Click any of them to go to the head of that branch. 151 | 152 | * when the commit graph gets really complex, the line connecting two commits 153 | is broken. Click on any line segment (not on a dot or a dangling 154 | arrowhead) and the diff pane changes to show details for that line segment 155 | -- all parents and children are shown. 156 | 157 | * as above, but if you click on the *arrowhead*, you will be taken to the 158 | portion of the tree where the other end of the arrowhead would go to. 159 | Your "current" commit is still the same; this is just a way of 160 | "connecting" two pieces of the graph that are otherwise too far away. 161 | 162 | * "Follows:" and "Precedes:" show the nearest tag before and after the 163 | commit for each branch that the commit is a part of. For example, if you 164 | find the commit for a bugfix or a feature you want, this will tell you the 165 | minimum version you should upgrade to. 166 | 167 | # some other tricks 168 | 169 | * expand the diff view by using the spin control that says "Lines of 170 | context"; the default value is 3. 171 | 172 | * find the "origin" of any line visible in the "diff" pane by right clicking 173 | and choosing "Show origin of this line". This does not make sense for 174 | lines prefixed by a plus sign of course. 175 | 176 | * go to a specific commit by SHA: click on a commit, hit TAB twice to get 177 | the focus onto the SHA1 field, then type in the first few characters of 178 | the SHA you want. 179 | 180 | On Linux, you can grab the current SHA into a terminal command line by 181 | using the middle-click. 182 | 183 | * Just above the diff view are some additional widgets. One of them is a 184 | drop-down called `Line diff`. Be sure to try the `Color words` diff, 185 | especially when long lines have had just one or two changes. 186 | 187 | Similarly, the "Ignore space change" checkbox is useful when blocks have 188 | indentation changes that cause the normal diff to look a lot noisier than 189 | it should be. 190 | 191 | * Finally, for a great birds-eye view of all the **refs** in a repo (but not 192 | the commits between them), try `gitk --all --simplify-by-decoration`. 193 | -------------------------------------------------------------------------------- /articles/ignore-rules.mkd: -------------------------------------------------------------------------------- 1 | % rules for .gitignore and the like 2 | 3 | Those of you who have read the manual for gitignore will have noticed that, 4 | while the rules for precedence of the various files (pattern sources) are very 5 | clear, the rules for the actual exclusion patterns are somewhat less so. 6 | They're certainly accurate, but newcomers have to read very carefully if they 7 | want to do anything moderately complex with their exclude rules. 8 | 9 | One day (2009-02-18, ~16:00 IST, to be precise), 'doener' (Björn Steinbrink) 10 | came up with some much simpler rules that said the same thing, and -- building 11 | on the insight that his rules gave me -- I came up with these: 12 | 13 | ---- 14 | 15 | Note that rule 1 merely *modifies* rules 2 and 3, it does not supercede or 16 | preclude them. 17 | 18 | 1. If your pattern ends with a slash, it matches only directories (and their 19 | contents) 20 | 2. If there is no slash otherwise, it matches that name, at any depth in the 21 | tree 22 | 3. If there is a slash anywhere else, it matches that name, relative to the 23 | .gitignore (or `$GIT_WORK_TREE` if the pattern is from one of the other 24 | pattern sources like `.git/info/exclude` etc) 25 | 26 | The wildcards (`*` and `?`) do not match slashes, but otherwise the patterns 27 | are normal shell globs as defined by fnmatch(3) with the `FNM_PATHNAME` flag 28 | set. 29 | 30 | ---- 31 | 32 | Just for completeness, the pattern source priorities are, highest to lowest: 33 | 34 | * command line 35 | * the deepest .gitignore that applies to this path 36 | * shallower .gitignore files until you get to `$GIT_WORK_TREE` 37 | * patterns in .gitignore files are relative to the location of the 38 | gitignore file, not to the `$GIT_WORK_TREE` 39 | * `$GIT_DIR/info/exclude` 40 | * core.excludesfile 41 | 42 | 43 | -------------------------------------------------------------------------------- /articles/reflog.mkd: -------------------------------------------------------------------------------- 1 | % what the heck is a *reflog* and why is it so important? 2 | 3 | # what is it 4 | 5 | * a reflog is a very special "branch" that records each position of HEAD 6 | in the last 30 days (by default). So removed branches won't be purged by 7 | prune until after waiting for 30 days, when the last reference to them 8 | will finally be released. 9 | 10 | * reflog history is not shared -- it is exclusive to your repository. This 11 | is the only thing you lose if you clone a project as a means of performing 12 | a backup. 13 | 14 | # how do I visualise it 15 | 16 | * the basic reflog commands are like this (the relative date is my 17 | preference; see `git help log` for other choices) 18 | 19 | # activity on HEAD, including timestamp 20 | git reflog show --date=relative 21 | # same, on some_branch 22 | git reflog show --date=relative some_branch 23 | 24 | * a good way to visualise the reflog is `git show-branch -g` (or `-gN`, 25 | where N is some integer). This shows reflog info for the branch specified 26 | (defaulting to the current branch), including topological relationships 27 | and relative time. This is useful if you had a lot of rebases or amended 28 | commits and you think you might need one of them back :-) 29 | 30 | It takes a little getting used to, so here're some hints: 31 | 32 | * the top of each vertical line represents a prior position of HEAD (or 33 | whatever branch you specified), with the latest one being the extreme 34 | left column 35 | * for each commit, the non-blank commit vertically below is its parent 36 | commit (merge commits are represented by a "-" sign) 37 | * so when you see a dip in the "line of peaks", you know there was a 38 | reset to something earlier followed by a new set of commits 39 | * very likely, the top commit to the right of any such "dip" is probably 40 | unreachable 41 | 42 | # why would I need it 43 | 44 | * you can recover commits made on a detached head 45 | 46 | * you can fix a non-bare push 47 | 48 | # cool tricks 49 | 50 | [Here](tools/git-reflogk)'s a neat tool that shows you reflog output but 51 | using gitk -- the graphical viewer. Don't knock it until you've tried it :-) 52 | 53 | ---- 54 | 55 | ^[based on a comment in ]^ 56 | -------------------------------------------------------------------------------- /articles/server-sizing.mkd: -------------------------------------------------------------------------------- 1 | 2 | 3 | % sizing a server for git 4 | 5 | **Update Dec 2013**: this was written some years ago; the measurements could 6 | only have gotten better now... 7 | 8 | ---- 9 | 10 | How big a server do you need to host git repos? These are my current thoughts 11 | on this, and they're essentially what I sent in an internal email to someone 12 | at work who asked about that as well as network bandwidth concerns when the 13 | server is used from multiple sites over a WAN. 14 | 15 | Note: the specific question also asked how many "concurrent" users a git 16 | server with a given spec could handle. However, a typical developer will only 17 | interact with the git server on average 2-6 times a day, with each interaction 18 | lasting at most for a few seconds. That's it! 19 | 20 | This is why "concurrent users" is not a meaningful measure, unless everyone 21 | hits "push" or "pull" at exactly the same time :-) 22 | 23 | Anyway, here are some details, from the point of view of a typical 24 | "enterprise" use of a VCS. Be sure to read the last section on the [one 25 | operation](#repack) that *can* stress out a git server. 26 | 27 | # bandwidth usage: {-} 28 | 29 | * the initial clone (like when a new team member joins the project) 30 | transfers data about the size of the repository. This is highly 31 | compressed but it could still be large. 32 | 33 | Just as a point of reference, I pulled down the entire Linux kernel 34 | repository just now. It was 310 MB and took about 20 minutes to come in 35 | on my home DSL line here. 36 | 37 | Please note this is about 4 years and 3 months worth of changes on a 38 | project with hundreds of active developers; you have to ask yourself if 39 | your project is really that large. 40 | 41 | * after the initial clone, regular updates (git pull/fetch) take very little 42 | time. 43 | 44 | Again, to give you a point of reference, I had an older copy of the linux 45 | kernel tree that was last updated 6 days ago. I just pulled down those 6 46 | days worth of changes, and the actual data trasferred was about 400 KB 47 | (yes, **kilo** bytes, for 6 days of changes in a very active project) 48 | 49 | * if you're worried that the initial clone will be a killer when an entire 50 | remote site (with, say, 50 people) joins the repository, don't worry. Git 51 | has ways to get around that also, if you are worried about it. 52 | 53 | There's a command called "git bundle" which lets you package up the entire 54 | repository into one file, which you can transfer one time to the other 55 | site. At the other site, they share that bundle file on their LAN 56 | (instead of each person essentially getting the same file on the WAN), and 57 | clone from it. After the clone is done, you make a one-line change to the 58 | config file (change the URL to point to the real server instead of a local 59 | file!) and it's done. 60 | 61 | What all this means is, for the cost of one extra command on the server 62 | and one extra command on each client, you have "seeded" an entire site 63 | with just one download :-) 64 | 65 | # CPU usage {-} 66 | 67 | Git does take some CPU time to pack up a repository, especially to supply an 68 | initial clone. Even in the initial clone, on a decent dual-core machine it 69 | will be as fast as the hard disk can read the repository data, which means 70 | pretty fast. On subsequent pull/push operations, it is very fast. 71 | 72 | The CPU-bound operations in day to day git operations are 73 | 74 | * compressing each file (aka "blob") using zlib 75 | * computing deltas (differences) between objects to optimise sending data 76 | when someone clones or pulls 77 | 78 | Zlib is quite efficiently coded, and besides, is so widely used in so many 79 | other parts of a modern operating system, that it is not much of an issue. 80 | 81 | Computing deltas is definitely more CPU hungry (as well as memory hungry), but 82 | -- except on the initial clone -- it happens incrementally so any 83 | decent/recent dual-core CPU should be able to handle it very fast. 84 | 85 | > ---- 86 | > ^^Further details on this, courtesy charon on #git: 87 | 88 | > Even when computing deltas to send, git reuses packs. This means that 89 | objects that are already packed are not delta compressed again -- 90 | send-pack just uses the existing delta-compressed form. Anyway it doesn't 91 | really send the _entire_ pack, only the parts that are relevant, so this 92 | works fine. 93 | 94 | > As a result, cpu usage on the server is now mostly in the "counting 95 | objects" phase (i.e., figuring out what to send), which is not much of a 96 | load.^^ 97 | 98 | # memory {-} 99 | 100 | A machine with about 512 MB ***free*** RAM will probably work fine for most 101 | development style repositories. In practice this means about 1 GB total RAM, 102 | assuming no other big programs are running. Note that all this is transient 103 | use -- there is no "long running background process" in a normal git install 104 | that sits around hogging memory. If no one is accessing the repository 105 | (push/pull/clone), then no memory is used. 106 | 107 | The only time you get into memory problems under normal use is if you have 108 | files that are really large, like more than 50 MB or so. (We're not talking 109 | about total repo size here; we're talking one individual file). If you have 110 | any such files in the repo (or worse, many such files), it may be a good idea 111 | to run some benchmarks first. [I'm being very conservative here; in practice 112 | I'm sure much larger files can be used without trouble but at some point it 113 | will cause problems. That may be 100MB, or 250MB, or whatever but it will 114 | happen...] 115 | 116 | Otherwise there's nothing inherently in git to gobble up memory except the 117 | [repack](#repack) operation mentioned in the last section. 118 | 119 | # disk {-} 120 | 121 | As I mentioned in one of my presentations, git takes about 1/20th the size of 122 | an SVN repository, so this should not be a concern. However, this does assume 123 | the "repack" operation referred to below is being run at least once a month or 124 | so. 125 | 126 | # stressing out a git server {#repack -} 127 | 128 | The only time git does anything that seriously stresses the machine (in ***all 129 | respects***, not just CPU) is a "repack" operation that (by default) runs very 130 | rarely. You can, if you wish, set a config variable to make it never happen 131 | automatically, and just do it manually about once a month, or by cron at 4am 132 | on Sunday, or whatever suits you. 133 | 134 | I tried a full repack of the linux kernel tree on my desktop, and it took 135 | approximately 700 MB of RAM, 5:20 minutes elapsed time, and 7:04 minutes of 136 | CPU time (CPU time is more than elapsed time because parts of this repacking 137 | are multi-threaded). 138 | 139 | So -- if you schedule it at night or Sunday morning or whatever, you'll be 140 | fine. Don't worry about it... 141 | -------------------------------------------------------------------------------- /articles/tias.mkd: -------------------------------------------------------------------------------- 1 | % try it and see... 2 | 3 | It's easy to forget that a lot of git's features, including features concerned 4 | with remote repos like fetch/pull/push, can be safely and easily tried out 5 | **locally**: 6 | 7 | * start with an empty directory 8 | * create a new bare repo in it (e.g., `git init --bare b.git`). This is 9 | your **server** repo! 10 | * clone this one or more times (e.g., `git clone b.git c1; git clone b.git 11 | c2`). These are your **developer** repos; you can treat each one as 12 | belonging to a different developer. The "server" repo you cloned from 13 | will be defined as the remote called "origin" in each of these clones. 14 | 15 | Now you're ready to test out whatever features you want using any or all of 16 | the clones you created. 17 | 18 | Notice that we are simply using the local file system as the transport 19 | protocol. People familiar with URLs on a browser might recognise this as eqvt 20 | to `file:///full/path/to/something`, and indeed that is exactly what git 21 | treats it as. 22 | 23 | Using ssh or http merely changes 24 | 25 | * the URL used 26 | * the authentication required and permissions granted by the server 27 | 28 | What **does NOT change** is the behaviour of most git commands! 29 | 30 | This means you can play with git to your heart's content in some temporary 31 | directory. There's no danger of messing up a real repo, or of getting 32 | side-tracked by connectivity or permissions or even speed issues, which might 33 | happen if you tried this with a real server. 34 | 35 | If playing on a test repo is not sufficient for your needs, you can replace 36 | the "create a new bare repo" step with a clone of one of your real repos. For 37 | example, I might do this: 38 | 39 | git clone --bare git://github.com/sitaramc/gitolite.git b.git 40 | 41 | and that would give me a "b.git" that is a bare repo that starts out with all 42 | the code and branches that my real server repo has. 43 | 44 | ---- 45 | 46 | Note: the [terminology](terminology.html) page may also be useful, especially the section 47 | on "accessing remote repositories". 48 | 49 | -------------------------------------------------------------------------------- /articles/uses-of-index.mkd: -------------------------------------------------------------------------------- 1 | % Why the index/staging area is so useful 2 | 3 | > Newcomers to git often ask why there is such a thing as the index, and 4 | what use is it. They'd rather just do `git add -A; git commit` each time 5 | to avoid thinking about the index at all, because it seems like one extra 6 | (and needless) complication. 7 | 8 | > So... what use is this, apart from confusing you with multiple names like 9 | index, staging area, and cache? 10 | 11 | 12 | # what is the index {-} 13 | 14 | The index (or any of its other names) is essentially a "holding area" for 15 | changes that will be committed when you next do `git commit`. That is, unlike 16 | other VCSs, a "commit" operation does not simply take the current working tree 17 | and check it as-is into the repository. The index allows you to control what 18 | parts of the working tree go into the repository on the next "commit" 19 | operation. 20 | 21 | That should be sufficient background to appreciate (in abstract terms) the 22 | following discussion. 23 | 24 | # staging helps you split up one large change into multiple commits {-} 25 | 26 | Let's say you worked on a large-ish change, involving a lot of files and quite 27 | a few different subtasks. You didn't actually commit any of these -- you were 28 | "in the zone", as they say, and you didn't want to think about splitting up 29 | the commits the right way just then. (And you're smart enough not to make the 30 | whole thing on honking big commit!) 31 | 32 | Now the change is all tested and working, you need to commit all this 33 | properly, in several clean commits each focused on one aspect of the code 34 | changes. 35 | 36 | With the index, just stage each set of changes and commit until no more 37 | changes are pending. Really works well with `git gui` if you're into that 38 | too, or you can use `git add -p` or, with newer gits, `git add -e`. 39 | 40 | # staging helps in reviewing changes {-} 41 | 42 | Staging helps you "check off" individual changes as you review a complex 43 | commit, and to concentrate on the stuff that has not yet passed your review. 44 | Let me explain. 45 | 46 | Before you commit, you'll probably review the whole change by using `git 47 | diff`. If you stage each change as you review it, you'll find that you can 48 | concentrate better on the changes that are not yet staged. 49 | 50 | `git gui` is great here. It's two left panes show unstaged and staged changes 51 | respectively, and you can move files between those two panes 52 | (stage/unstage) just by clicking on the icon to the left of the filename. 53 | 54 | Even better, you can even stage *partial changes* to a file. In the right 55 | pane of `git gui`, right click on a change that you approve of and choose 56 | "stage hunk". *Just that change* (not the entire file) is now staged; in 57 | fact, if there are other, unstaged, changes in that same file, you'll find 58 | that the file now appears on *both* top and bottom left panes! 59 | 60 | ^^[Do remember, however, that if the change is really complex maybe you should 61 | split it into multiple commits!]^^ 62 | 63 | # staging helps when a merge has conflicts {-} 64 | 65 | When a merge happens, changes that merge cleanly are updated both in the 66 | staging area as well as in your work tree. Only changes that did not merge 67 | cleanly (i.e., caused a conflict) will show up when you do a `git diff`, 68 | or in the top left pane of `git gui`. 69 | 70 | Again, this lets you concentrate on the stuff that needs your attention -- the 71 | merge conflicts. 72 | 73 | # staging helps you keep extra local files hanging around {-} 74 | 75 | Usually, files that should not be committed go into `.gitignore` or the 76 | local variant, `.git/info/exclude`. 77 | 78 | However, sometimes you want a local change to a file that cannot be excluded 79 | (which is not good practice but can happen sometimes). For example, perhaps 80 | you upgraded your build environment and it now requires an extra flag or 81 | option for compatibility, but if you commit the change to the Makefile, the 82 | other developers will have a problem. 83 | 84 | Of course you have to discuss with your team and work out a more permanent 85 | solution, but right now, you *need* that change in your working tree to do 86 | *any* work at all! 87 | 88 | Another situation could be that you want a new local file that is temporary, 89 | and you don't want to bother with the ignore mechanism. This may be some test 90 | data, a log file or trace file, or a temporary shell script to automate some 91 | test... whatever. 92 | 93 | In git, all you have to do is never to stage that file or that change. That's 94 | it. 95 | 96 | # staging helps you sneak in small changes ;-) {-} 97 | 98 | Let's say you're in the middle of a somewhat large-ish change and you are told 99 | about a very important bug that needs to be fixed asap. 100 | 101 | The usual recommendation is to do this on a separate branch, but let's say 102 | this fix is really just a line or two, and can be tested just as easily 103 | without affecting your current work. 104 | 105 | With git, you can quickly make and commit *only that change*, without 106 | committing all the other stuff you're still working on. 107 | 108 | Again, if you use `git gui`, whatever's on the bottom left pane gets 109 | committed, so just make sure only that change gets there and commit, then 110 | push! 111 | 112 | ## a word of warning... {-} 113 | 114 | While the first 3 use cases are perfectly legitimate and useful uses of the 115 | index, this last example could be dangerous if you get carried away. You 116 | might end up committing something that is not tested *exactly*, because you 117 | tested with the contents of the work tree, which is not the same as the index 118 | that is being committed. 119 | 120 | Of course, using a powerful DVCS does not absolve you from the responsibility 121 | of thinking :-) So if you want to be 100% sure, there is a simple way to test 122 | only the staged code: 123 | 124 | # stash away the changes to git-tracked files that you have not staged yet 125 | git stash save --keep-index 126 | # now do your tests on the exact stuff being committed 127 | make; make test # etc... 128 | # when satisfied, commmit 129 | git commit 130 | 131 | # now bring the stashed changes back to continue normal work 132 | git stash pop 133 | 134 | If you need to understand how/why this works, [ask 135 | me](mailto:sitaramc@gmail.com), otherwise just use it and be happy :-) 136 | -------------------------------------------------------------------------------- /articles/vc-habits.mkd: -------------------------------------------------------------------------------- 1 | # version control habits of good developers {-} 2 | 3 | @@gray((not necessarily git-specific))@@ 4 | 5 | This article is based on -- 6 | a blog post that is well worth checking out, especially if you want more 7 | details. However, this article represents my priorities on this matter, and 8 | most of the words are mine. 9 | 10 | - **USE IT**! If you don't use version control you should get out of the 11 | software development profession! 12 | 13 | - **check-in often**: check-in when some logical unit of work is done 14 | (compiles OK after major changes, or some feature is complete, or some 15 | test was passed, etc.). "going home for the day" is NOT a logical unit of 16 | work; ideally you should not treat the version control system as a "backup 17 | mechanism". If you do this sort of time-based check-in, "*the danger is 18 | that if you have to revert because you've made some disastrous changes, 19 | you won't have a sane state to revert to*." 20 | 21 | - **check-in bite sized chunks**: large check-ins are hard to review, and 22 | harder to revert 23 | - if you check-in 20 "logical units of work" in one shot, and the 3rd 24 | and the 14th are bad, you'll have to revert the entire check-in, 25 | remove changes 3 and 14, and then check-in again. If you checked them 26 | all in separately, you can revert just the changes that were not 27 | acceptable, while retaining all the other stuff 28 | - if the "feature" is too large, create a branch and check-in locally 29 | - however, check-ins should be **atomic** -- for instance, a related 30 | change in 2 ".c" files and a ".h" file should not become 3 check-ins 31 | if those changes all depend on each other. 32 | 33 | - **make sure you include everything that is needed to rebuild the 34 | project**: (this is more for single-developer projects) since we don't 35 | want to check-in binary files like executables and libraries, we normally 36 | set up the VCS to ignore some files based on extension or whatever. This 37 | list has to be made carefully, and reviewed once in a while, otherwise 38 | something that is important to the build may get left out! 39 | - in git, you can temporarily rename the .gitignore file and then do a 40 | "git status" (or run "git gui") to see the files that git is ignoring 41 | - or you can clone the entire project into a new directory and see if it 42 | compiles 43 | - or you can run: 44 | 45 | git ls-files --exclude-standard -o -i 46 | 47 | - **take backups**! Don't use the version control system as a backup medium 48 | 49 | - **keep "data" outside the "source" tree**: putting data in the same 50 | directory as the source tree is a very bad practice, and in fact I expect 51 | seasoned programmers who are reading this to go "huh? somebody actually 52 | does stupid things like that?" :-) Small amounts of textual data used to 53 | trigger specific tests are OK, and may even benefit from version control 54 | in the sense that a test suite is an integral part of any software with 55 | longevity. But anything larger than that, and more so if they are binary 56 | blobs, should NOT be in the repository. 57 | 58 | - **don't break the build**! 59 | 60 | - **update ("git pull") regularly**: otherwise, you risk a large effort in 61 | resolving conflicts when you eventually do pull 62 | 63 | - **write good check-in comments**: this helps people understand the 64 | evolution of the project much better over a long period of time. Don't 65 | forget the second purpose of a VCS is annotation: who changed it, what did 66 | they change, and **why**. There's more on this in the next section. 67 | 68 | - **use branches or holding areas**: branching and merging is cheap and 69 | easy, and helps you keep things separate in your own mind too. Having a 70 | hierarchy of branches is very useful. For instance: 71 | - "master" is what is pulled from/pushed to the repository, "work" is 72 | where you do the day-to-day development, "ut" is where you unit test, 73 | pulling specific commits from "work" for a build and a test, "st-it" 74 | is for integration test/system test, and so on. 75 | - in git, it's easy to use the "gitk" gui to pick individual changes 76 | from another branch into the current one 77 | 78 | ## write useful, readable, commit messages {-} 79 | 80 | A good description of this is at . But 81 | briefly, try and stick to the following guidelines: 82 | 83 | * the first line of the commit message (often called a "subject") should be 84 | a *summary* of the entire commit 85 | * it should not be more than about 70 characters long 86 | * it should include any reference info (like bug number, issue number, etc) 87 | if applicable 88 | * the rest of the message ("body") can be pretty much anything, but leave a 89 | blank line between the "subject" and the "body" 90 | 91 | Git uses the "subject" part in many places and it is very useful to have a 92 | short, meaningful subject line for each commit. 93 | 94 | Needless to say, these guidelines are easier to follow if you follow the 95 | earlier ones; for example, it's easier to write a useful commit message if you 96 | have not dumped four unrelated changes into the same commit ;-) 97 | -------------------------------------------------------------------------------- /common-header.html: -------------------------------------------------------------------------------- 1 |

2 | git notes main page 3 | | 4 | gitolite main page 5 | | 6 | license 7 |

8 | 9 |

10 | 11 | 12 | IMPORTANT NOTE: 13 | 14 | although this page has a "gitolite.com" URL, this is not about gitolite. 15 | That's just an artifact of "sitaramc.github.com" being translated to 16 | "gitolite.com" and so ALL my git related stuff gets carried over. 17 | Gitolite documentation has another /gitolite in the URL, so 18 | you can tell. My apologies for this confusion. 19 | 20 |

21 | -------------------------------------------------------------------------------- /grafts.todo: -------------------------------------------------------------------------------- 1 | 2009-08-08 17:53 Sat 2 | 17:17:50 < wereHamster> evilissimo: take a look at grafts and man git-filter-branch 3 | 17:17:51 < Gitbot> evilissimo: the git-filter-branch manpage can be found at 4 | http://git.or.cz/man/git-filter-branch 5 | 17:26:14 evilissimo: maybe http://sitaramc.github.com/concepts/grafting.html also :-) [been a while 6 | since I wrote it though] 7 | 17:33:25 < charon> sitaram: heh. i should go to the district magistrate and ask for a filter-branch ;) 8 | 17:35:11 < charon> sitaram: on a more serious note, i think the last example is rather misleading 9 | 17:35:38 < charon> of course you can change history like that, but since a5 keeps its tree, the difference 10 | between a1 and a5 will still have all the changes of a2-a4 11 | 17:35:55 < charon> similarly for a4..a9 having the changes a5-a8 12 | 17:36:31 < charon> well, ok, the latter would be the case for a normal merge too... 13 | 17:36:55 charon: aaah... lemme check 14 | 17:37:57 < charon> making a9 look like a merge is also rather weird unless it had no changes of its own to begin 15 | with 16 | 17:38:57 < charon> i think this particular trick should be an example for rebase --onto, not grafts :) 17 | -------------------------------------------------------------------------------- /images/corporate-use-1.gv: -------------------------------------------------------------------------------- 1 | digraph G { 2 | // graph size in inches 3 | // size ="8,8"; 4 | rankdir=LR 5 | edge [dir=both]; 6 | 7 | node [image="server.png", shape=plaintext] 8 | 9 | C [label="Chennai\nserver"] 10 | Z [label="Zurich \nserver"] 11 | 12 | node [label="dev PC", image="workstation_t.png", shape=plaintext] 13 | 14 | z1 -> Z 15 | z2 -> Z 16 | z3 -> Z 17 | z4 -> Z 18 | 19 | C -> c1 20 | C -> c2 21 | C -> c3 22 | C -> c4 23 | 24 | edge [color=red]; 25 | Z -> C [style=bold,minlen=2] 26 | } 27 | -------------------------------------------------------------------------------- /images/corporate-use-2.gv: -------------------------------------------------------------------------------- 1 | digraph G { 2 | rankdir = BT 3 | splines=false 4 | nodesep = 1.0 5 | edge [dir=none] 6 | 7 | compound = true 8 | 9 | subgraph clusterCS { 10 | label="Chennai server\n\ \ \ " 11 | 12 | cs2 [shape=box, label="bare repo\non server", style=filled, fillcolor=green] 13 | node [style=invis] 14 | edge [style=invis] 15 | cs1 -> cs2 16 | } 17 | subgraph clusterCL { 18 | label="Commits on\nChennai Lead PC" 19 | 20 | node [shape=box, style=rounded, style=filled, fillcolor=lightblue] 21 | c1 [label = "Commit #1\n.gitignore"] 22 | c2 [label = "Commit #2\nSource\nFiles"] 23 | c1 -> c2 24 | } 25 | 26 | cs2 -> c2 [lhead=clusterCL, ltail=clusterCS, label = "push", dir=back, color=red, constraint = false] 27 | } 28 | -------------------------------------------------------------------------------- /images/corporate-use-3.gv: -------------------------------------------------------------------------------- 1 | digraph G { 2 | rankdir = BT 3 | splines=false 4 | nodesep = 1.0 5 | edge [dir=none] 6 | 7 | node[shape=circle, style=filled, width=0.2 label=""] 8 | 9 | subgraph cluster1 { 10 | label="zurich-master"; fontcolor=green 11 | labelloc=b 12 | color=white 13 | node[fillcolor=green] 14 | t -> u [weight=50] 15 | u -> v [weight=50] 16 | w [shape=doublecircle] 17 | v -> w [weight=50] 18 | } 19 | 20 | subgraph cluster2 { 21 | label="[master]"; fontcolor=blue 22 | labelloc=b 23 | color=white 24 | node[fillcolor=blue] 25 | a -> b -> c 26 | c -> d [weight=50] 27 | e [shape=doublecircle] 28 | d -> e [weight=50] 29 | } 30 | 31 | c -> t 32 | } 33 | -------------------------------------------------------------------------------- /images/corporate-use-4.gv: -------------------------------------------------------------------------------- 1 | digraph G { 2 | rankdir = BT 3 | splines=false 4 | nodesep = 1.0 5 | edge [dir=none] 6 | 7 | node[shape=circle, style=filled, width=0.2, label=""] 8 | 9 | subgraph cluster1 { 10 | label="origin/zurich-master"; fontcolor=green 11 | labelloc=b 12 | color=white 13 | node[fillcolor=green] 14 | t -> u [weight=50] 15 | u -> v [weight=50] 16 | w [shape=doublecircle] 17 | v -> w [weight=50] 18 | } 19 | 20 | subgraph cluster2 { 21 | label="[master]"; fontcolor=blue 22 | labelloc=b 23 | color=white 24 | node[fillcolor=blue] 25 | a -> b -> c 26 | c -> d [weight=50] 27 | d -> e 28 | mc [shape=doublecircle] 29 | e -> mc [minlen=3,weight=50] 30 | } 31 | 32 | c -> t 33 | 34 | w -> mc 35 | 36 | } 37 | -------------------------------------------------------------------------------- /images/corporate-use-5.gv: -------------------------------------------------------------------------------- 1 | digraph G { 2 | rankdir = BT 3 | splines=false 4 | nodesep = 1.0 5 | edge [dir=none] 6 | 7 | node[shape=circle, style=filled, width=0.2, fixedsize=true, label=""] 8 | 9 | subgraph cluster1 { 10 | label="origin/chennai-master"; fontcolor=green 11 | labelloc=b 12 | color=white 13 | node[fillcolor=green] 14 | t -> u [weight=50] 15 | u -> v [weight=50] 16 | w [shape=doublecircle] 17 | v -> w [weight=50] 18 | } 19 | 20 | subgraph cluster2 { 21 | label="[test-merge]"; fontcolor=blue 22 | labelloc=b 23 | color=white 24 | node[fillcolor=blue] 25 | a -> b -> c 26 | c -> d [weight=50] 27 | d -> e [weight=50] 28 | mc [shape=doublecircle] 29 | e [shape=doublecircle, label=" master\n\n\n\n", fontcolor=blue] 30 | e -> mc [minlen=3,weight=50] 31 | } 32 | 33 | c -> t 34 | 35 | w -> mc 36 | 37 | } 38 | -------------------------------------------------------------------------------- /images/corporate-use-6.gv: -------------------------------------------------------------------------------- 1 | digraph G { 2 | rankdir = BT 3 | splines=false 4 | nodesep = 1.0 5 | edge [dir=none] 6 | 7 | node[shape=circle, style=filled, width=0.2, fixedsize=true, label=""] 8 | 9 | subgraph cluster1 { 10 | label="origin/chennai-master"; fontcolor=green 11 | labelloc=b 12 | color=white 13 | node[fillcolor=green] 14 | t -> u [weight=50] 15 | u -> v [weight=50] 16 | w [shape=doublecircle] 17 | v -> w [weight=50] 18 | } 19 | 20 | subgraph cluster2 { 21 | label="[master], test-merge"; fontcolor=blue 22 | labelloc=b 23 | color=white 24 | node[fillcolor=blue] 25 | a -> b -> c 26 | c -> d [weight=50] 27 | d -> e [weight=50] 28 | mc [shape=doublecircle] 29 | e -> mc [minlen=3,weight=50] 30 | } 31 | 32 | c -> t 33 | 34 | w -> mc 35 | 36 | } 37 | -------------------------------------------------------------------------------- /images/git.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git.png -------------------------------------------------------------------------------- /images/git/demo-09-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git/demo-09-01.png -------------------------------------------------------------------------------- /images/git/demo-09-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git/demo-09-02.png -------------------------------------------------------------------------------- /images/git/demo-09-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git/demo-09-03.png -------------------------------------------------------------------------------- /images/git/demo-09-04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git/demo-09-04.png -------------------------------------------------------------------------------- /images/git/demo-09-05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git/demo-09-05.png -------------------------------------------------------------------------------- /images/git/demo-09-06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git/demo-09-06.png -------------------------------------------------------------------------------- /images/git/demo-09-07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git/demo-09-07.png -------------------------------------------------------------------------------- /images/git/demo-09-08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git/demo-09-08.png -------------------------------------------------------------------------------- /images/git/demo-09-09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git/demo-09-09.png -------------------------------------------------------------------------------- /images/git/demo-09-10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git/demo-09-10.png -------------------------------------------------------------------------------- /images/git/demo-09-11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git/demo-09-11.png -------------------------------------------------------------------------------- /images/git/demo-10-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git/demo-10-01.png -------------------------------------------------------------------------------- /images/git/demo-10-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git/demo-10-02.png -------------------------------------------------------------------------------- /images/git/demo-10-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git/demo-10-03.png -------------------------------------------------------------------------------- /images/git/demo-11-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git/demo-11-01.png -------------------------------------------------------------------------------- /images/git/demo-11-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git/demo-11-02.png -------------------------------------------------------------------------------- /images/git/demo-11-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git/demo-11-03.png -------------------------------------------------------------------------------- /images/git/demo-11-04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git/demo-11-04.png -------------------------------------------------------------------------------- /images/git/demo-11-05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git/demo-11-05.png -------------------------------------------------------------------------------- /images/git/demo-11-06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git/demo-11-06.png -------------------------------------------------------------------------------- /images/git/demo-12-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git/demo-12-01.png -------------------------------------------------------------------------------- /images/git/demo-12-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git/demo-12-02.png -------------------------------------------------------------------------------- /images/git/demo-12-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git/demo-12-03.png -------------------------------------------------------------------------------- /images/git/demo-12-04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git/demo-12-04.png -------------------------------------------------------------------------------- /images/git/demo-12-05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git/demo-12-05.png -------------------------------------------------------------------------------- /images/git/demo-13-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git/demo-13-01.png -------------------------------------------------------------------------------- /images/git/demo-13-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git/demo-13-02.png -------------------------------------------------------------------------------- /images/git/demo-13-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git/demo-13-03.png -------------------------------------------------------------------------------- /images/git/flow-CVCS.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 20 | 27 | 32 | 33 | 40 | 45 | 46 | 53 | 54 | 71 | 73 | 74 | 76 | image/svg+xml 77 | 79 | 80 | 81 | 82 | 86 | 95 | CVCSs 106 | 113 | 123 | WorkingDirectory 137 | 144 | RemoteRepository(centralserver) 170 | 174 | 178 | Checkout/Update 192 | Commit 202 | 210 | Metadatafor VCS 224 | 232 | 233 | 234 | -------------------------------------------------------------------------------- /images/git/gitk-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git/gitk-1.png -------------------------------------------------------------------------------- /images/git/gitk-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git/gitk-2.png -------------------------------------------------------------------------------- /images/git/gitk-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git/gitk-3.png -------------------------------------------------------------------------------- /images/git/gui-blame-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git/gui-blame-1.png -------------------------------------------------------------------------------- /images/git/gui-blame-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git/gui-blame-2.png -------------------------------------------------------------------------------- /images/git/gui-blame-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git/gui-blame-3.png -------------------------------------------------------------------------------- /images/git/gui-blame-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git/gui-blame-4.png -------------------------------------------------------------------------------- /images/git/gui-blame-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git/gui-blame-5.png -------------------------------------------------------------------------------- /images/git/projects-sans-vcs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/git/projects-sans-vcs.png -------------------------------------------------------------------------------- /images/gitlfy-fig1-gui-blame.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/gitlfy-fig1-gui-blame.gif -------------------------------------------------------------------------------- /images/gitlfy-fig2-branch-visual.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/gitlfy-fig2-branch-visual.gif -------------------------------------------------------------------------------- /images/gitlfy-fig3-stitching-pattern.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/gitlfy-fig3-stitching-pattern.gif -------------------------------------------------------------------------------- /images/index-use-review-2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 20 | 27 | 32 | 33 | 40 | 45 | 46 | 53 | 54 | 71 | 73 | 74 | 76 | image/svg+xml 77 | 79 | 80 | 81 | 82 | 86 | 95 | Uses of index:Reviewingchanges 116 | 123 | 133 | 140 | Changed files 150 | 158 | 166 | You've reviewedall but one file, andnow you want tofocus on that one.So, use 'git gui' tostage the onesyou're done with 212 | file3.c 222 | file1.cfile1.hfile2.cREADME.txt 244 | 245 | 246 | -------------------------------------------------------------------------------- /images/index-use-review-3.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 20 | 27 | 32 | 33 | 40 | 45 | 46 | 53 | 54 | 71 | 74 | 75 | 77 | 78 | 80 | image/svg+xml 81 | 83 | 84 | 85 | 86 | 90 | 99 | Uses of index:Reviewingchanges 120 | 127 | 137 | 144 | Changed files 154 | 162 | 170 | And finally, whenthat is also done,you can stage thattoo... 196 | file3.c 207 | file1.cfile1.hfile2.cREADME.txt 229 | 230 | 231 | -------------------------------------------------------------------------------- /images/index-use-review-4.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 20 | 27 | 32 | 33 | 40 | 45 | 46 | 53 | 54 | 71 | 74 | 75 | 77 | 78 | 80 | image/svg+xml 81 | 83 | 84 | 85 | 86 | 90 | 99 | Uses of index:Reviewingchanges 120 | 127 | 137 | 144 | Changed files 154 | 162 | 170 | ...and committhe new versions! 186 | file3.c 197 | file1.cfile1.hfile2.cREADME.txt 219 | 234 | 235 | 236 | -------------------------------------------------------------------------------- /images/server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/server.png -------------------------------------------------------------------------------- /images/vc/clean-again.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/vc/clean-again.png -------------------------------------------------------------------------------- /images/vc/clean-cli.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/vc/clean-cli.png -------------------------------------------------------------------------------- /images/vc/clean-gui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/vc/clean-gui.png -------------------------------------------------------------------------------- /images/vc/commit-gui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/vc/commit-gui.png -------------------------------------------------------------------------------- /images/vc/dag-br-tag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/vc/dag-br-tag.png -------------------------------------------------------------------------------- /images/vc/dag-br.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/vc/dag-br.png -------------------------------------------------------------------------------- /images/vc/dag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/vc/dag.png -------------------------------------------------------------------------------- /images/vc/dirty-cli.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/vc/dirty-cli.png -------------------------------------------------------------------------------- /images/vc/dirty-gui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/vc/dirty-gui.png -------------------------------------------------------------------------------- /images/vc/empty-windows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/vc/empty-windows.png -------------------------------------------------------------------------------- /images/vc/empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/vc/empty.png -------------------------------------------------------------------------------- /images/vc/init-done-win1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/vc/init-done-win1.png -------------------------------------------------------------------------------- /images/vc/init-done-win2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/vc/init-done-win2.png -------------------------------------------------------------------------------- /images/vc/init-done-winb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/vc/init-done-winb.png -------------------------------------------------------------------------------- /images/vc/init-done.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/vc/init-done.png -------------------------------------------------------------------------------- /images/vc/init-win1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/vc/init-win1.png -------------------------------------------------------------------------------- /images/vc/init-win2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/vc/init-win2.png -------------------------------------------------------------------------------- /images/vc/init-win3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/vc/init-win3.png -------------------------------------------------------------------------------- /images/vc/init-win4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/vc/init-win4.png -------------------------------------------------------------------------------- /images/vc/init-winb1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/vc/init-winb1.png -------------------------------------------------------------------------------- /images/vc/init-winb2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/vc/init-winb2.png -------------------------------------------------------------------------------- /images/vc/inside-dotgit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/vc/inside-dotgit.png -------------------------------------------------------------------------------- /images/vc/remote.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/vc/remote.png -------------------------------------------------------------------------------- /images/vc/repo-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/vc/repo-1.png -------------------------------------------------------------------------------- /images/vc/repo-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/vc/repo-2.png -------------------------------------------------------------------------------- /images/vc/repo-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/vc/repo-3.png -------------------------------------------------------------------------------- /images/vc/repo-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/vc/repo-4.png -------------------------------------------------------------------------------- /images/vc/repo-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/vc/repo-5.png -------------------------------------------------------------------------------- /images/vc/repo-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/vc/repo-6.png -------------------------------------------------------------------------------- /images/vc/repo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/vc/repo.png -------------------------------------------------------------------------------- /images/vc/sampleproj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/vc/sampleproj.png -------------------------------------------------------------------------------- /images/vc/staged-cli.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/vc/staged-cli.png -------------------------------------------------------------------------------- /images/vc/staging-gui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/vc/staging-gui.png -------------------------------------------------------------------------------- /images/vc/worktree-symbol.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/vc/worktree-symbol.png -------------------------------------------------------------------------------- /images/vc/worktree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/vc/worktree.png -------------------------------------------------------------------------------- /images/workstation_t.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitaramc/git-notes/3f4e803c2ad6bc8c7d0512be81775a87be7aee5c/images/workstation_t.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gitolite.com 5 | 6 | 7 | 8 | http://gitolite.com/gitolite/index.html 9 | 10 | 11 | -------------------------------------------------------------------------------- /index2.mkd: -------------------------------------------------------------------------------- 1 | % Notes on Git 2 | 3 | .#d 4 | 5 | Git is a **Distributed** Version Control System. Most VCSs you know (like 6 | CVS, Subversion, Clearcase, Perforce, and VSS) are centralised. A Distributed 7 | VCS allows you to make frequent, local, commits to checkpoint your work while 8 | you're still perfecting the code -- you cannot do this with a centralised VCS. 9 | 10 | These are my notes about git. I started writing them for my own 11 | understanding, almost like cheat sheets, but they may be useful for others 12 | also. 13 | 14 | .#d 15 | 16 | 17 | 18 | >
19 | > **Looking for gitolite documentation? Click [here](gitolite/index.html)**. 20 | >
21 | 22 |
23 | 24 | .#t 25 | 26 | .#t cellspacing=10 27 | 28 | .#d 29 | 30 | ### Why git? {-} 31 | 32 | Why is git so popular? If you're just curious, but not curious enough to dig 33 | in like a developer, maybe [this article](git-lfy.html), which I wrote in 34 | 2008, will help. 35 | 36 | ### What is git? {-} 37 | 38 | If you want to understand git, we have @@red(**slideshows**)@@. 39 | 40 | * an [introduction](vc.html) to version control and the central concepts 41 | behind git -- for those who have never used *any* version control tool. 42 | * what makes [git](git.html) so powerful -- for those who know something 43 | about version control but not git. 44 | 45 | ### git usage {-} 46 | 47 | In the ["git usage"](usage.html) page you will find various tips and traps, 48 | information for command line and GUI users, Windows users, running a git 49 | server, plus a quick set of hints for people familiar with traditional VCSs 50 | like SVN and CVS. 51 | 52 | .#d 53 | 54 | ### Popular links {-} 55 | 56 | These links show up several times a day on #git (the git channel on IRC) 57 | 58 | * git as a [deployment](deploy.html) tool 59 | * [Git concepts simplified](gcs.html) has lots of diagrams explaining git 60 | * [Try it and see!](tias.html) -- shows how easy it is to safely try out 61 | almost any git feature on your own userid 62 | 63 | ### Other write-ups {-} 64 | 65 | A whole bunch of [other articles](articles.html) on git 66 | 67 | ### Refreshers {-} 68 | 69 | Git and DVCS [terminology](terminology.html) 70 | 71 | .#t 72 | 73 | ---- 74 | 75 | @@gray(There are also some [older articles and write-ups](archived/index.html) 76 | that may still be relevant and useful, but I have not revisited them for a 77 | while now. Caveat reader!)@@ 78 | 79 | ---- 80 | 81 | # License {-} 82 | 83 | (c) Copyright Sitaram Chamarty, sitaramc@gmail.com. This documentation is 84 | provided under a [Creative Commons Attribution-NonCommercial-ShareAlike 3.0 85 | Unported License](http://creativecommons.org/licenses/by-nc-sa/3.0/). 86 | -------------------------------------------------------------------------------- /license.mkd: -------------------------------------------------------------------------------- 1 | % License 2 | 3 | © Copyright Sitaram Chamarty, sitaramc@gmail.com. This documentation is 4 | provided under a [Creative Commons Attribution-NonCommercial-ShareAlike 3.0 5 | Unported License](http://creativecommons.org/licenses/by-nc-sa/3.0/). 6 | 7 | However, of necessity, there are code examples within those documents. I 8 | believe that the principle of fair use should cover use of those snippets; see 9 | especially factors 3 and 4 in the list of factors 10 | [here](http://en.wikipedia.org/wiki/Fair_use#Fair_use_under_United_States_law). 11 | 12 | If you're not convinced that it would be fair use, then you may consider those 13 | code snippets, as well as associated "comments" if any, to be under the GPLv2 14 | license. 15 | -------------------------------------------------------------------------------- /mkdoc: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # run from git-notes as "./mkdoc" 4 | 5 | OUTDIR="/tmp/doc2" 6 | OUTDIR="$HOME/data/gits/sitaramc.github.com" 7 | 8 | rm $OUTDIR/*.html 9 | rm -rf $OUTDIR/images 10 | mkdir $OUTDIR/images 11 | rm -rf $OUTDIR/archived 12 | mkdir $OUTDIR/archived 13 | 14 | for mkd in `find . -name "*.mkd" | sort` 15 | do 16 | base=$(basename $mkd .mkd) 17 | [[ $mkd =~ archived ]] && base="archived/$base" 18 | 19 | pdh -t html-N -i $mkd -o $OUTDIR/$base.html 20 | done 21 | 22 | mkdir -p $OUTDIR/tools 23 | cp tools/* $OUTDIR/tools 24 | # -- XXX do we need this? -- cp images/* $OUTDIR/images 25 | 26 | # cleanup 27 | rm fig*.png 28 | 29 | cp index.html $OUTDIR 30 | 31 | cd $OUTDIR 32 | mkdir -p 1-basic-usage gcs the-list-and-irc 33 | echo '"Try it and see" has moved' > 1-basic-usage/tias.html 34 | echo '"Git concepts simplified" has moved' > gcs/index.html 35 | echo '"Git as a deployment tool" has moved' > the-list-and-irc/deploy.html 36 | -------------------------------------------------------------------------------- /tools/git-reflogk: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Usage: ./reflogk [N] 4 | # optional argument N (defaults to 10) to limit how many reflog entries to go 5 | # back 6 | 7 | # shows the following, using gitk: 8 | # - unreachable entries among the first N reflog entries, cropped at their 9 | # common merge-base (which ought to be far enough away!) 10 | # - the topmost references that are not reachable from some other 11 | # reference 12 | 13 | # sound confusing? try it...! 14 | 15 | # grab top N entries from the reflog 16 | refs=`git reflog -${1:-10} | cut -f1 -d' ' | sort -u` 17 | 18 | # find their common merge-base 19 | export common 20 | for r in $refs 21 | do 22 | common=$(git merge-base ${common:-$r} $r) 23 | done 24 | echo $common 25 | 26 | # for each ref, we use the special construct that says "just this commit and 27 | # *not* any of its parents" (see git help rev-parse) 28 | parents=$(git for-each-ref --format='%(objectname)^! %(objecttype) %(*objecttype)' | 29 | grep commit | cut -d' ' -f1) 30 | gitk HEAD $refs $parents --not $common 31 | -------------------------------------------------------------------------------- /usage/commands.mkd: -------------------------------------------------------------------------------- 1 | 2 | 3 | % useful commands 4 | 5 | # grep {-} 6 | 7 | `git grep` is very, **very**, powerful. It has pretty much all the normal 8 | grep options, plus: 9 | 10 | * doesn't search files that are not revisioned (untracked, excluded/ignored, 11 | etc) 12 | * with `--cached`, looks only in the cache 13 | * with one or more ref names, searched only within those revisions 14 | * can take a pattern, like `*.c`, to restrict the files searched 15 | * can do `--and`, `--or`, `--not`, etc with patterns. This is a pretty big 16 | wow. As says: 17 | 18 | git grep -e ';;' --and --not -e 'for *(.*;;' -- '*.c' 19 | 20 | which searches for ';;' in all C files, unless they occur in a typical 21 | `for (;;) {` type of construct. 22 | 23 | * finally, there's a somewhat gratuitously thrown in `--all-match` option, 24 | which says "match any of these strings, but print matches only from files 25 | that have *all* of them". I wonder whose scratch that was... ;-) 26 | 27 | # log and show {-} 28 | 29 | * `git lga` is pretty cool; lga is an alias in my config for 30 | 31 | log --graph --pretty=oneline --abbrev-commit --decorate --all 32 | 33 | * Check the logs to see what's happened recently 34 | 35 | git log [--stat] -[p] [-n ] 36 | git log "@{yesterday}.." 37 | # note the suffix "..", since the default is prefix "..", which is 38 | # probably not what you want 39 | git log somefile.c 40 | 41 | * `git show` is almost an alias for `git log -p -n 1`. In general, `git 42 | show` does the right thing: shows a commit as a commit, a tree as a plain 43 | "ls", etc. But if you're printing a large blob you better use a pager or 44 | redirect! 45 | 46 | git show [ HEAD^ | HEAD^^ | HEAD@{3} | origin | origin/master | etc ] 47 | git show 7a8b9c # or some hex number; shows you the object 48 | git show HEAD~3:file.c # get file.c from 3 versions back 49 | 50 | # reflog {-} 51 | 52 | ...see this more detailed [note](reflog.html) 53 | 54 | # show-branch {-} 55 | 56 | * `git show-branch -a` is useful to get a bird's eye view of all your 57 | branches and their topological relationships. 58 | * `git show-branch -gN` (N is some number) shows you reflog info for the 59 | current branch, including topological relationships and relative time. 60 | This is useful if you had a lot of rebases or amended commits and you 61 | think you might need one of them back :-) See 62 | [reflog](reflog.html) for more on this 63 | * if you need serious troubleshooting with branches, use the following. It 64 | may be useful in some contexts where `git lg` is too complex to figure out 65 | what tip contains what commit, and you are unable to use gitk 66 | 67 | git show-branch $(git show-ref -h |cut -c41-) 68 | 69 | # cherry (not cherry-pick) {-} 70 | 71 | * summary: `+` shows you commits you have that the 'upstream' doesn't 72 | 73 | git cherry -v upstream [head] 74 | 75 | * detail: for every commit in 'head' that doesn't exist in 'upstream' 76 | * prefix `-` if there is at least an *equivalent* commit 77 | * prefix `+` if there's not even that 78 | 79 | * TIP: if you're trying to cut some branches (like `git branch --merged`) 80 | * put the candidate to be cut **on the right side**, and 81 | * make sure there are no `+`s in the output 82 | 83 | # cat-file (repo object) and ls-tree (tree object) {-} 84 | 85 | Note: I'm not sure what, if any, is the difference between `show` and 86 | `cat-file -p` for "blob" objects. For commits there is a subtle 87 | difference. (Try it) 88 | 89 | # any object 90 | git cat-file [ -t | -s | -p ] 789abc 91 | # find the type or size of an object, or pretty print it 92 | # If it's a blob, I'd use use "git show" until we find out what 93 | # "pretty" means for arbitrary blobs :-) 94 | git cat-file blob 789abc # cat the object 95 | 96 | # any tree 97 | git ls-tree # files and directories, top level only 98 | git ls-tree -l # also show the size of the object 99 | git ls-tree -d # only directories 100 | git ls-tree -r # recurse, only files 101 | git ls-tree -r -d # recurse, only directories 102 | git ls-tree -r -t # recurse, both directories and files 103 | 104 | # ls-files {-} 105 | 106 | To get listings of various types of files, use `git ls-files`. The common 107 | but less intuitive ones are shown here, the rest can be had from the man page: 108 | 109 | # deleted files and modified files (deleted files are also counted as 110 | # modified, so may come up twice... 111 | git ls-files -d -m 112 | # what's in the index; includes files that were "git add"ed 113 | git ls-files -s 114 | # conflicted files 115 | git ls-files -u 116 | # "other files"; includes EVERYthing not in d/m/s, I think 117 | # seems to be equal to untracked + ignored 118 | git ls-files -o 119 | # untracked files only 120 | git ls-files --exclude-standard -o 121 | # ignored files only 122 | git ls-files --exclude-standard -o -i 123 | 124 | -------------------------------------------------------------------------------- /usage/gotchas-cli.mkd: -------------------------------------------------------------------------------- 1 | ## simple "gotcha"s at the command line {-} 2 | 3 | * `git log rev` and `git diff rev` go in different directions. Log shows 4 | backward from the rev given, while diff goes forward from rev to the 5 | working directory. 6 | 7 | * many commands inherit options from lower level programs and their man 8 | pages will appear incomplete. Read carefully to see what other commands' 9 | options are applicable to this one. For example, `git-log` inherits from 10 | `git-rev-list` and `git-diff-tree`. 11 | 12 | * using `cp -a` copy instead of `git clone` will screw the timestamps. A 13 | subsequent `git add .` will make it look like every file has changed, in 14 | terms of just the time stamp. *Fix this by using `git status`, which 15 | updates the index for such cases as a side effect.* 16 | 17 | * confused by `HEAD^`, `HEAD~1`, etc.? `man git-rev-parse` has a good 18 | diagram. And remember the reflog is quite different and has a different 19 | syntax (`HEAD@{2`}). 20 | 21 | * cloning a repo: the following two commands are different. The first one 22 | clones the repository using a mix of copy (for the smaller files in the 23 | ".git" directory ) and hard linking (for the larger files), so it's quite 24 | fast even for large repositories. 25 | 26 | The second one uses git's packfile transfer protocol, which makes no 27 | assumptions about the original and the clone being on the same file system 28 | or even machine. It will almost certainly take more time and disk space. 29 | 30 | git clone foo bar # versus 31 | git clone file:///foo bar 32 | 33 | -------------------------------------------------------------------------------- /usage/gui.mkd: -------------------------------------------------------------------------------- 1 | 2 | 3 | % git's native GUI tools 4 | 5 | Git comes with 3 GUI tools, but two of them are a bit more important than the 6 | third so we'll focus on those for now. 7 | 8 | These two tools are very powerful; if you don't like the command line, you can 9 | quite easily stick to them and get by for most purposes. Briefly, they are: 10 | 11 | * `git gui` to stage and unstage files (equivalent to `git add`), commit, 12 | and push 13 | * `gitk` to get a bird's eye view your current branch, or `gitk --all` to 14 | view all branches, local and remote 15 | 16 | Git's GUI interfaces let you do almost anything that you **normally** need to 17 | do -- all the simple straightforward things as well as some sophisticated 18 | things. 19 | 20 | # git gui {-} 21 | 22 | `git gui` shows you the current state of your work area with respect to the 23 | currently checked-out branch. In the top left pane, it shows you what files 24 | are changed with respect to the last commit. In the bottom left pane it shows 25 | you what files have been marked "ready for commit" -- only these changes will 26 | go into the next commit if you commit now. 27 | 28 | (Git allows you to keep some changes "pending", without committing them. The 29 | "ready to commit" part is called the "index", "staging area", or "cache" in 30 | the documentation, so the bottom left pane is showing you what is in the 31 | "index". Check out [why the index is useful](uses-of-index.html) for more). 32 | 33 | In either case, the changes made to the currently selected file are shown on 34 | the right pane. 35 | 36 | There are a lot of things you can do in this GUI, but here are the basic 37 | things: 38 | 39 | * you can click on the icon to the left of each file name to move it back 40 | and forth between the two areas ("staged, ready for commit" <-> "unstaged, 41 | not to be committed right now") 42 | * you can also type in a suitable commit message and click the "commit" 43 | button. This commits the change to your local repository 44 | * you can also "push" the changes to some central repository so that others 45 | can pull them 46 | 47 | # gitk {-} 48 | 49 | `gitk` (or `gitk --all`, which is what I use more often) shows you a visual 50 | tree of all the commits that have happened on this repository. It is a very 51 | powerful tool, allowing you to do all sorts of things like 52 | 53 | * create a new branch 54 | * checkout (switch to) a different branch 55 | * delete a branch 56 | * create a tag 57 | * pick commits from some other branch to apply to the current branch 58 | * show differences between any two commits 59 | * traverse the tree of commits 60 | * search for commits based on all sorts of criteria 61 | 62 | There's a much more detailed description of [gitk's features](gitk.html) if 63 | you need it. 64 | 65 | # where you *really* need the command line {-} 66 | 67 | One common task that is needlessly complex in both the GUIs is `git pull`. In 68 | a properly setup repository that has been cloned from the project master or 69 | something like that, getting the latest changes is just a matter of typing 70 | `git pull`. In `git gui`, described above, this takes 4 steps, although there 71 | is a reason for that complexity :-) 72 | 73 | # further reading {-} 74 | 75 | There's a really thorough introduction to these tools, including lots of 76 | screenshots, at . The page has an 77 | excellent example "project" that is simple enough that you can concentrate on 78 | the git features being demonstrated, and the author goes into quite a few 79 | things you can do with the GUI tools. 80 | 81 | Some minor caveats: 82 | 83 | * if you're on Linux you'll just have to ignore some of the installation 84 | related stuff 85 | 86 | * if you're on Windiws, I suggest you stick to the ssh that comes with git. 87 | Putty and plink have (in my experience supporting gitolite users) always 88 | been problems and I would avoid them like the plague. YMMV. 89 | 90 | One tip: if you installed Putty/plink anyway, and now msysgit is not 91 | talking to the repository properly, `unset GIT_SSH` is apparently the 92 | thing to do. Again, YMMV and all that. 93 | 94 | * some of the stuff dealing with other servers (like adding a remote, 95 | pulling from someone's IP address, etc.), may work differently in a 96 | corporate environment. 97 | 98 | -------------------------------------------------------------------------------- /usage/legacy.mkd: -------------------------------------------------------------------------------- 1 | # tips for legacy VCS migrants! {-} 2 | 3 | * **gotcha**: `git add somefile` adds the **current** content of `somefile` 4 | to the staging area. Changes made after this do not affect `git commit` 5 | unless you again do a `git add` or use the `-a` option to `git commit`. 6 | 7 | * **gotcha**: `commit` means to your local repo, not to the "server"! 8 | 9 | * these commands/options effectively bypass the "index" or "staging area", 10 | **but the INDEX is really a wonderful concept, and you really should not 11 | bypass it like this**. See [why the index is 12 | useful](uses-of-index.html) or 13 | 14 | 15 | git diff HEAD # to see changes you made 16 | git add # to tell git about new files... 17 | git commit -a # ...and let git figure out changed and deleted files before committing 18 | 19 | * CVS equivalence 20 | 21 | CVS GIT 22 | --- --- 23 | checkout clone 24 | update pull 25 | checkin commit + push 26 | add add 27 | remove rm 28 | ??? mv 29 | 30 | -------------------------------------------------------------------------------- /usage/server.mkd: -------------------------------------------------------------------------------- 1 | % git on the server 2 | 3 | `git` is a *distributed* version control system (DVCS), and every developer 4 | thus has his/her own repository. A central server is therefore not a 5 | technical requirement, but more of a practical and/or administrative one, if 6 | at least as a place for the "official" version of your repo. 7 | 8 | I have only 2 things to say about the server environment: 9 | 10 | * install Gitolite 11 | 12 | * for additional piece of mind, set the following 13 | 14 | git config core.logAllRefUpdates true 15 | git config transfer.fsckObjects true 16 | 17 | # protocols that git uses {-} 18 | 19 | Git uses the following protocols to access remote repositories; example URLs 20 | are given in parentheses: 21 | 22 | * **ssh** (`ssh://user@my.server/path/to/repo`). Authentication is handled 23 | by ssh. See the section on "gitolite and other tools" for authorisation. 24 | 25 | * **http/https**: (`http://my.server/path/to/repo`). Authentication is 26 | handled by the web server. Authorisation *can* be handled by gitolite if 27 | you're using "smart http" (see 'man git-http-backend'). 28 | 29 | * **local file system**: (`file:///path/to/repo`). Authentication is not 30 | relevant (you're already logged in). 31 | 32 | Authorisation is handled by OS file-system permissions, but there's a 33 | little twist. Using OS permissions, or even filesystem ACLs, you can only 34 | get repo-level granularity for reads and writes (i.e., you can say Alice 35 | can read the repo, Bob can read and write, and Carol cannot do either, but 36 | that;s it). 37 | 38 | * **git**: (`git://my.server/path/to/repo`). This is an *UNAUTHENTICATED* 39 | protocol, useful only for allowing clones of publicly accessible repos. If 40 | they can reach port 9418 on your server, they can get it. Pushes are 41 | disabled by default, and -- needless to say -- you must *NEVER* enable 42 | them! 43 | 44 | This protocol is handled by the special 'git-daemon' program, which you 45 | can run either directly or via inetd/xinetd. Please see its man page etc 46 | for details. 47 | 48 | # gitolite and other tools for authorisation {-} 49 | 50 | There are many situations where you need to establish limits on what someone 51 | can do. When you have a number of developers, with varying levels of 52 | experience and expertise, accessing a number of repos, and different branches 53 | in different repos have different levels of "importance", you need some 54 | serious authorisation tool. 55 | 56 | [Gitolite][gl] is the best such tool I know (blame author bias if you don't 57 | agree!). It comes with a [quick 58 | install](http://sitaramc.github.com/gitolite/index.html#qi) section, plus lots 59 | and lots of [documentation][gld]. 60 | 61 | [gl]: http://github.com/sitaramc/gitolite 62 | [gld]: http://gitolite.com/gitolite 63 | 64 | Other tools exist, but they are all web-based. "Gerrit code review" is the 65 | most powerful of the free ones, but it's much more focused on (and much more 66 | useful for) code review / workflow enforcement. Less capable tools are 67 | gitorious, gitlab, and so on (I don't believe any of them has the kind of 68 | branch level and file/directory level access controls that Gitolite has). 69 | 70 | For open source projects or if you don't mind paying a small amount of money, 71 | Github is very nice. (Gitolite's primary host is Github, and I have no other 72 | relationship with them than being a free user). Github's access control is 73 | not at all fine-grained so it's best if it's used only as a "meeting point" 74 | server for your team, and not as a "source of truth". 75 | 76 | -------------------------------------------------------------------------------- /usage/tips-1.mkd: -------------------------------------------------------------------------------- 1 | 2 | 3 | % tips for the beginner 4 | 5 | # set up your gitconfig {-} 6 | 7 | This is `$HOME/.gitconfig`. Whenever you add the `--global` option to the 8 | `git config` command, it acts on the global gitconfig file. 9 | 10 | Setup your identity 11 | 12 | git config --global user.email your.name@your.com 13 | git config --global user.name "your name" 14 | 15 | Setup to edit files from within "git gui"; replace "gvim -f" with whatever you 16 | prefer 17 | 18 | git config --global guitool.Edit.cmd 'gvim -f $FILENAME' 19 | git config --global guitool.Edit.noconsole yes 20 | git config --global guitool.Edit.needsfile yes 21 | 22 | If you intend to use the command line more than the GUI, please do check out 23 | my gitconfig (at the end of this page) for many useful examples that may save 24 | you lots of time and trouble. 25 | 26 | ## my `~/.gitconfig` file {-} 27 | 28 | This is as of Dec 2013. One of these days I'll stop being lazy and explain 29 | some of them :-) 30 | 31 | [user] 32 | name = Sitaram Chamarty 33 | email = sitaram@atc.tcs.com 34 | [color] 35 | ui = true 36 | [core] 37 | pager = less -R 38 | compression = 6 39 | 40 | [rerere] 41 | enabled = 1 42 | [diff] 43 | mnemonicprefix = true 44 | tool = kdiff3 45 | [merge] 46 | tool = kdiff3 47 | [gui] 48 | editor = gvim 49 | [guitool "edit"] 50 | cmd = gvim -f $FILENAME 51 | noconsole = yes 52 | needsfile = yes 53 | [guitool "mergetool"] 54 | cmd = git mergetool -y -t kdiff3 $FILENAME 55 | noconsole = yes 56 | needsfile = yes 57 | [push] 58 | default = matching 59 | [mergetool] 60 | keepBackup = false 61 | 62 | # everyday ones 63 | [alias] 64 | s = status -s -b -uno 65 | 66 | b = branch 67 | ba = branch -a -v -v 68 | bc = !git-branch-check 69 | 70 | ci = commit -v -uno 71 | co = checkout 72 | 73 | d = diff -C 74 | dw = diff -C -w 75 | ds = diff -C --stat 76 | dsp = diff -C --stat -p 77 | dcw = diff -C --word-diff 78 | 79 | du = diff -C @{u} 80 | dwu = diff -C -w @{u} 81 | dcwu= diff -C --word-diff @{u} 82 | 83 | l = log -C --decorate 84 | ls = log -C --stat --decorate 85 | lsp = log -C --stat -p --decorate 86 | 87 | lgbw= log --graph --boundary '--format=%h %ar %d %s' 88 | lg = log --graph --boundary '--format=%Cblue%h%Creset %Cgreen%ar%Creset %Cblue%d%Creset %s' 89 | lga = log --graph --boundary '--format=%Cblue%h%Creset %Cgreen%ar%Creset %Cblue%d%Creset %s' --all 90 | # this is the most commonly used one, it turns out! 91 | l19 = log --graph --boundary '--format=%Cblue%h%Creset %Cgreen%ar%Creset %Cblue%d%Creset %s' --all -19 92 | # and this one can be a real lifesaver on a complex tree 93 | lsd = log --graph --boundary '--format=%Cblue%h%Creset %Cgreen%ar%Creset %Cblue%d%Creset %s' --all --simplify-by-decoration 94 | # log left-right; requires argument like A...B (3 dots) 95 | lglr= log --graph --boundary '--format=%Cblue%h%Creset %Cgreen%ar%Creset %Cblue%d%Creset %s' --boundary --left-right --cherry-pick 96 | 97 | # this is so frequent for me... 98 | pom = push origin master 99 | # pushall = "!f() { git remote | map -p git push; }; f" 100 | pall = !git remote | map -p git push 101 | 102 | rl = reflog show --date=relative 103 | 104 | ru = remote update 105 | 106 | sl = stash list 107 | sp = stash pop 108 | ss = stash save 109 | # "show-branch -g=N" can't be aliased for N easily, so we stop here: 110 | sb = show-branch 111 | # pg sbt master pu -- if the last line is 'master' and not 'master^' 112 | # or 'master~N' then pu is a descendent of master 113 | sbt = show-branch --topics 114 | sbs = show-branch --sha1-name 115 | 116 | ka = !gitk --all 117 | kdo = !gitk --date-order 118 | kado = !gitk --all --date-order 119 | kasd = !gitk --all --simplify-by-decoration 120 | 121 | z = squirrel --repo=/home/sitaram/imli/tech/repos/squirrel 122 | nb = squirrel --repo=/home/sitaram/imli/tech/repos/notebook 123 | 124 | # exotic ones 125 | [alias] 126 | # checkpoint and checkpoint recover 127 | cp = !git stash save $(date +%F--%T) && git stash pop --index 128 | cpr = "!f() { git fsck | grep commit | cut -d' ' -f3 | while read hash; do git rev-parse --verify --no-revs --quiet $hash^2 2>/dev/null && echo $hash | xargs git rev-list --since=${1:-1day} -1; done | xargs -L 1 git log --format=%at:%h -1 | sort|cut -f2 -d: | xargs -L 1 git log --graph --oneline --format='%Cblue%h %Cgreen(%ar) %Creset%s' -3 ; }; f" 129 | 130 | # when was this file last updated, on each local branch 131 | wwflu = "!f() { for b in $(git rev-parse --symbolic --branches); do echo -e `git log --format=%at:%ar -1 $b -- \"$1\"`\\\\t$b; done | sort -r |cut -f2 -d: ; }; f" 132 | 133 | # branch fast-forward: update from upstream if it's a fast-forward 134 | # (obsoleted now by 'git-branch-check but keep it just in case) 135 | # bff = "!f() { for i; do [[ $(git rev-parse $i) == $(git merge-base $i $i@{upstream}) ]] && git checkout $i && git merge $i@{upstream} && git checkout -; done; }; f" 136 | 137 | graphviz = "!f() { echo 'digraph git {' ; git log --pretty='format: %h -> { %p }' \"$@\" | sed 's/[0-9a-f][0-9a-f]*/\"&\"/g' ; echo '}'; }; f" 138 | 139 | cat = -p cat-file -p 140 | 141 | top = !eval cd "$(pwd)/$(git rev-parse --show-cdup)" && pwd 142 | 143 | # exotic ones that I might forget they exist; keep them at the end of the file 144 | # for 'cat' or 'tail' to show them easily 145 | [alias] 146 | ls-del = ls-files -d 147 | ls-mod = ls-files -m # this will include deleted files also 148 | ls-new = ls-files --exclude-standard -o 149 | # this one is a MUST have 150 | ls-ign = ls-files --exclude-standard -o -i 151 | lsfiles = ls-files --exclude-per-directory=.gitignore \ 152 | --exclude-from=.git/info/exclude \ 153 | -v -d -o -m -s -u 154 | 155 | sk = !gitk --date-order $(git stash list | cut -d: -f1) --not --branches --tags --remotes 156 | 157 | d1 = !gitk --date-order $(git log -g --pretty=%H) --not --branches --tags --remotes 158 | d2 = !gitk --date-order $(git fsck | grep "dangling.commit" | cut -f3 -d' ') --not --branches --tags --remotes 159 | -------------------------------------------------------------------------------- /usage/tips-2.mkd: -------------------------------------------------------------------------------- 1 | 2 | 3 | % slightly more advanced tips 4 | 5 | # how to remember what "..." does {-} 6 | 7 | Git's "..." operator is confusing, because it does different things in git 8 | diff and git log. Here's something that may help you reason it out. 9 | 10 | To start with, these points are fundamental: 11 | 12 | * the older revision is (normally) specified on the left side (LHS) 13 | * "diff" only works on two *endpoint* commits, regardless of how many 14 | commits exist in between those endpoints 15 | * however, "log" works on all the in between commits also 16 | * normal, everyday, usage is `git diff A..B`, meaning "changes from A to 17 | B", and `git log A..B`, meaning "commits in B but not in A". 18 | 19 | To those simple rules, add just one more (easy enough to remember): the 20 | "`...`" operator always involves the common ancestor somehow. 21 | 22 | With those rules in mind, you can keep track of what the double-dot and 23 | triple-dot mean very easily. 24 | 25 | Consider `git diff A...B`: 26 | 27 | * since the "`...`" is used, the common ancestor is involved 28 | * since diff can only deal with 2 end points, one of A or B has to make way 29 | for the common ancestor 30 | * since the common ancestor is older than A and B, clearly it has to appear 31 | on the left side, so A loses :-) 32 | 33 | And this becomes `git diff CA(A,B)..B`, where CA(A,B) is the common 34 | ancestor of A and B. Easy enough? 35 | 36 | Now look at `git log A...B` 37 | 38 | * again, the "`...`" is used, so the common ancestor is involved 39 | * since log is not constrained to only 2 endpoints like diff is, you don't 40 | have to discard A or B 41 | * so you show the commits between the common ancestor and A, *as well as* 42 | between the common ancestor and B 43 | 44 | So: `git log CA(A,B)..A` PLUS `git log CA(A,B)..B` 45 | 46 | # Easy way to remember what git reset's soft/hard/mixed do {-} 47 | 48 | ^^loosely based on ^^ 49 | 50 | Assume you start from a "everything is committed and golden" state. Let's 51 | pretend you came to this starting point via a `git checkout`: and then you 52 | edit a bunch of stuff, compile/test, and then `git add` and `git 53 | commit`: 54 | 55 | $ git checkout mywork 56 | ...edit edit edit... 57 | $ git add ... 58 | $ git commit 59 | 60 | If at this point you do a `git reset`, here's how the type of reset 61 | ("soft", "hard", or the default, which is "mixed") affects things: 62 | 63 | $ git checkout mywork 64 | # --hard resets to this point 65 | ...edit edit edit... 66 | # --mixed (default) resets to this point 67 | $ git add ... 68 | # --soft resets to this point 69 | $ git commit 70 | 71 | Also note, as gitster says, that `git commit --amend` makes the `git 72 | reset --soft` mostly redundant. 73 | 74 | -------------------------------------------------------------------------------- /usage/tips-3.mkd: -------------------------------------------------------------------------------- 1 | 2 | 3 | % advanced tips 4 | 5 | # backing up work in progress {-} 6 | 7 | This is how you can backup everything on your local repo that is not already 8 | on one of your remotes, including all untracked files not covered by the 9 | ignore mechanism. I use a script based on this to save my work to a remote 10 | server at regular intervals, in case of a disaster (hardware failure, etc) on 11 | the regular desktop. 12 | 13 | # sort of like stash; untracked files also saved 14 | git commit --allow-empty -m wip-index-state 15 | git add -A && git commit --allow-empty -m wip-worktree-state 16 | 17 | # make a temp branch (FIXME: should we do this first?) 18 | git branch wip-backup || 19 | die 'could not create wip-backup branch; aborting'; 20 | 21 | # unstash 22 | git reset --mixed HEAD^ 23 | git reset --soft HEAD^ 24 | 25 | # create the bundle and remove the temp branch 26 | git bundle create /tmp/sos.bdl --all --not --remotes 27 | git branch -D wip-backup 28 | 29 | # copy that file wherever you want, however you want... 30 | rsync /tmp/sos.bdl bkphost: # or scp, or whatever 31 | 32 | # conflicts on pull/merge {-} 33 | 34 | * try `gitk --merge conflicted_path` 35 | * `git diff MERGE_HEAD...HEAD` (note the *three* dots) shows you 36 | differences between the common ancestor and your HEAD. 37 | * similarly `git diff HEAD...MERGE_HEAD` shows you differences between 38 | the common ancestor and the branch you're trying to merge 39 | * `git checkout --conflict=diff3 conflicted_path` is a novel way of 40 | getting all 3 versions into the file so you can hack at it in vim 41 | * you can tell git blame to only show important changes, like so (pity it 42 | does not work with the GUI blame) 43 | 44 | git blame -C $(git merge-base HEAD MERGE_HEAD).. conflicted_path 45 | 46 | # log pickaxe and blame {-} 47 | 48 | * finding out when a particular change happened or who made it 49 | 50 | git log -S"some code line" file.c # why is this called pickaxe search? 51 | git blame -b file.c 52 | 53 | # what are all these "HEAD"s? {-} 54 | 55 | * `ORIG_HEAD`: pull or merge (or anything that moves HEAD drastically) 56 | leave a copy of the old head with this name. Reset can use it if needed. 57 | (see `man git-reset`). `reset` itself copies the old `HEAD` 58 | to `ORIG_HEAD`, though that seems less useful 59 | * `FETCH_HEAD`: records the branch you fetched from a remote repository 60 | with your last 'git-fetch' invocation 61 | * `MERGE_HEAD` records the commit(s) you are merging into your branch 62 | when you run 'git-merge' 63 | 64 | # garbage collection {-} 65 | 66 | NOTE: this section is old; I have not looked at it with respect to recent git 67 | versions. 68 | 69 | * Warning: `git gc --prune` is dangerous if others may be pushing to the 70 | repo at the same time! 71 | * Warning: `git gc` may **increase** the space used, since it even 72 | unpacks objects that were in packs if they became unreachable. This is 73 | the same thing as `git repack -Adf` (note the uppercase "A") 74 | 75 | * To bring the repo size down the bare minimum, you need *both* the 76 | following commands (neither command by itself does the whole job). Also 77 | Note the lowercase "a" on the "repack", which says you want to blindly 78 | discard unreachable objects instead of keeping them as loose objects. 79 | 80 | git repack -adf # kills in-pack garbage 81 | git prune # kills loose garbage 82 | 83 | * (from the do-you-really-want-to-do-this? department) 84 | 85 | git reflog expire --expire=10days --all 86 | # use expire-unreachable to limit it a bit 87 | # use branchname(s) instead of --all 88 | # units can be seconds, minutes, etc 89 | 90 | # recovering a dropped stash: {-} 91 | 92 | ## the GUI way {-} 93 | 94 | You dropped a stash that was created recently, and now you want to recover it. 95 | As long as you did not do a garbage collection in between, this should work: 96 | 97 | gitk $(git fsck | grep commit | cut -f3 -d' ') --since='1 week ago' 98 | 99 | The part within the parenthesis finds all unreachable commit objects and 100 | returns their hashes. If you never did a garbage collect there might be too 101 | many false positives so the `--since` clause (which you can adjust to whatever 102 | you want of course; mine is just an example) limits the display to commits 103 | created recently. 104 | 105 | A "stash" has a very recognisable, triangular, shape in the commit DAG, and 106 | with gitk you can visually find stashes really fast. For me, this is the kind 107 | of task that *calls out* for a GUI -- infrequently required, no conceivable 108 | need to automate, and containing data that stands out visually. 109 | 110 | ## the command line way {-} 111 | 112 | Writing something longer than that for a problem that occurs once in a blue 113 | moon is not my style (very low ROI!), but doener gave me this: 114 | 115 | git fsck --unreachable | grep commit | cut -d\ -f3 | 116 | xargs git log --no-walk --merges --grep='^\(WIP on \|On \)\((no branch)\|[^ ]\+\):' 117 | 118 | I knew about `--merges` but not `--no-walk`, and I anticipate using it a lot 119 | more in future :-) 120 | 121 | -------------------------------------------------------------------------------- /usage/usage.mkd: -------------------------------------------------------------------------------- 1 | % using git 2 | 3 | I've somewhat arbitrarily divided the miscellaneus tips into 4 | [beginner](tips-1.html), [intermediate](tips-2.html), and 5 | [advanced](tips-3.html). They all have a table of contents at the top so you 6 | can quickly check if anything could be of use to you. 7 | 8 | If you're ok with using the command line, these might interest you, there are 9 | some useful [git commands](commands.html), with some explanation or 10 | description -- grep, log, show, show-branch, cherry, and a few more. There's 11 | also a list of of some ["gotchas"](gotchas-cli.html) for the command line 12 | user. 13 | 14 | There's something for people wanting to run a [git server](server.html), 15 | although really, you should just install [gitolite](gitolite/index.html) and 16 | be done :-) 17 | 18 | Finally, there's also something for the [GUI user](gui.html), something for 19 | the [Windows user](windows.html), and something for people coming to git from 20 | [older legacy systems](legacy.html). 21 | -------------------------------------------------------------------------------- /usage/windows.mkd: -------------------------------------------------------------------------------- 1 | % git on windows 2 | 3 | # using git's GUI tools {-} 4 | 5 | Here's how to launch the GUI tools: 6 | 7 | * from the "git bash" command line (type `gitk` or `git gui`) 8 | * right click on a directory containing a repository and choose "git GUI 9 | here"; this launches `git gui` 10 | * if you already have one GUI open, launch the other one from the menus 11 | ("Repository -> Visualise History", or "File -> Start Git GUI") 12 | 13 | 14 | # using git at the command line {-} 15 | 16 | Git has a command line interface and two different GUI interfaces. 17 | 18 | The command line interface allows you to do pretty much anything, and is 19 | really the most convenient once you get used to it. You can get to the 20 | command line in one of the following ways: 21 | 22 | * (on Windows) click the "git" or "git bash" icon on your desktop/taskbar or 23 | wherever the install put it. This will start with the "git bash shell" 24 | set to whatever your "HOME" directory is. From there you can navigate 25 | (using the `cd` command) to wherever your repository is. 26 | 27 | * the "git bash shell" is almost a complete unix shell. So directories 28 | like `E:\some\path` are accessed as `/e/some/path`. 29 | 30 | * if your repository is in `E:\Myname\projects\projectname`, open 31 | `E:\Myname\projects` in the file manager, right click on 32 | `projectname`, and choose "git bash here". This will open the "git 33 | bash" command line positioned at that directory. 34 | --------------------------------------------------------------------------------