├── README.md ├── git-private-add-fetch └── git-private-push /README.md: -------------------------------------------------------------------------------- 1 | # git-private-push 2 | 3 | Create a hidden branch in remote repositories. 4 | 5 | Use `git private-push` to backup your work-in-progress branches, to keep 6 | history when frequently rebasing a branch without cluttering everyone's view, 7 | or to let others know the branch may get rebased at any time. 8 | 9 | `gitk` will display these refs in a nice gray color. 10 | 11 | **WARNING:** Hidden branches offer absolutely no security or privacy. 12 | They are just neither displayed nor fetched by default. 13 | 14 | **Features** 15 | 16 | * multiple private spaces 17 | * pushing multiple configured refs by single command (`private.*.push`) 18 | * automatic timestamping (`private.*.tsfmt`) 19 | * automatic force push (`private.*.force`) 20 | * customizable remote refs (`$USER`, `$EMAIL`, `$TS` and `$DST` are recognized) 21 | 22 | **Missing features** 23 | 24 | * man page! 25 | Sorry. `git private-push --help` will not work until a man page is added. 26 | Use `git-private-push --help` instead. 27 | 28 | **Internals** 29 | 30 | Git by default fetches from `refs/heads/`, `refs/tags/`. Pushing to a 31 | non-default subdirectory in `refs` will create a "hidden" branch which is not 32 | fetched unless asked for. 33 | 34 | ## Installation 35 | 36 | ### Requirements 37 | 38 | * git 39 | * bash 40 | 41 | ### How to install 42 | 43 | 1. Get the `git-private-push` and `git-private-add-fetch` scripts, by either: 44 | * Cloning this repository: 45 | `git clone https://github.com/csonto/git-private.git` 46 | * Downloading [the zip archive](https://github.com/csonto/git-private/archive/master.zip) 47 | and extracting it locally: 48 | `wget https://github.com/csonto/git-private/archive/master.zip && unzip master.zip` 49 | 2. Make the script callable form anywhere on your system, by either: 50 | * Adding the script files to a directory in your `$PATH`, e.g.: 51 | `cp /git-private-* /usr/local/bin/` 52 | * Creating a link to the script files from such a directory, e.g.: 53 | `ln -s /git-private-push /usr/local/bin/git-private-push` 54 | * Adding the directory where you downloaded the files to your `$PATH`, 55 | e.g.: 56 | `echo 'export PATH=":$PATH"' >> ~/.bashrc && source ~/.bashrc` 57 | 58 | ## Usage 59 | 60 | ### Configure private branches 61 | 62 | First, basic configuration of private branches. 63 | 64 | By default "junk" space is used. This default can be changed by changing 65 | `private.id` config option. 66 | 67 | By default each private space uses remote with the same name. For the default 68 | "junk" space you either need to create the remote: 69 | 70 | git remote add junk $URL 71 | 72 | Or change remote option like this: 73 | 74 | git config private.junk.remote origin 75 | 76 | You can also change the default remote for git working directory: 77 | 78 | git config private.remote origin 79 | 80 | Or change global default: 81 | 82 | git config --global private.remote origin 83 | 84 | See more bellow at [Configuration](#configuration). 85 | And have a look at [Examples](#concrete-examples). 86 | 87 | ### Pushing 88 | 89 | The `git private-push` is used as follows: 90 | 91 | git private-push [--id ID] [--force|--no-force] [BRANCH [DESTINATION]] 92 | 93 | Push to the default private space, named "junk": 94 | 95 | git private-push master 96 | 97 | Push a ref from remote to a private space named "wip", with custom destination: 98 | 99 | git private-push --id wip remotes/local/master local 100 | 101 | ### Fetching 102 | 103 | Add fetch config options to private "remote": 104 | 105 | git config --add remote.$remote.fetch "+refs/$path/*:refs/$path/$remote/*" 106 | 107 | e.g. for the private space named `wip` at the `origin` remote: 108 | 109 | git config --add remote.origin.fetch "+refs/wip/*:refs/wip/origin/*" 110 | 111 | Or use `git-private-add-fetch [ID]`. 112 | 113 | ### Concrete examples 114 | 115 | By default `.git/config` contains something like this: 116 | 117 | [remote "origin"] 118 | url = git@github.com:csonto/git-private.git 119 | # This is the default: 120 | fetch = +refs/heads/*:refs/remotes/origin/* 121 | 122 | The directory structure is up to you. In general you will likely want to follow 123 | up git's `refs/$PATH/$REMOTE` pattern. To fetch all refs from the remote add a 124 | line like this: 125 | 126 | fetch = +refs/*:refs/all/origin/* 127 | 128 | To fetch a subdirectory from the remote, add a line like this: 129 | 130 | fetch = +refs/wip/csonto/*:refs/wip/csonto/* 131 | 132 | Common options should go to `~/.gitconfig`, and project-specific options to 133 | `$PROJECT/.git/config`. 134 | 135 | Let's see something more useful... 136 | 137 | #### Backup 138 | 139 | I want a copy of my work stored on the server. I do not require history, single 140 | copy is good enough for me. 141 | 142 | git wip 143 | git wip BRANCH 144 | 145 | Eventually I might want to push uncommitted changes: 146 | 147 | git stash 148 | git wip "stash@{0}" stashed 149 | git stash pop 150 | 151 | If you want this to work for all your git repos, add a common configuration to 152 | `~/.gitconfig`: 153 | 154 | [private "wip"] 155 | # anything will do, timestamps are not used: 156 | tsfmt = "-" 157 | # ignoring TS, wip is not tracking history, only latest change is pushed: 158 | fmt = "$EMAIL/$DST" 159 | # the wip refs will be rewritten so push has to be forced: 160 | force = 1 161 | 162 | [alias] 163 | wip = private-push --id wip 164 | 165 | Add a project specific part - remote, list of branches - to project's 166 | `.git/config`. 167 | 168 | For each branch to store run: 169 | 170 | git config --add private.wip.push BRANCH 171 | 172 | To use different remote for this project add: 173 | 174 | git config private.wip.remote REMOTE 175 | 176 | The configuration will look like this (without comments): 177 | 178 | [private "wip"] 179 | # by default remote with same name (thus "wip") will be used. 180 | # You can use your own git server for backups: 181 | #remote = private 182 | 183 | # refs to backup with git wip: 184 | push = master 185 | push = gh-pages 186 | # add more here... 187 | 188 | Now you could do `git wip` and it will push the listed refs (`master` and 189 | `gh-pages`) to `refs/wip/user@example.com/BRANCH` 190 | (`refs/wip/user@example.com/master` and `refs/wip/user@example.com/gh-pages`.) 191 | 192 | Anything what is in your `refs` can be pushed, if you have another remote 193 | (`local`) set up, remote heads can be pushed like this: 194 | 195 | git config --add private.wip.push remotes/local/master 196 | 197 | If you want to keep the refs short use different name: 198 | 199 | git config --add private.wip.push "remotes/local/master local" 200 | 201 | To automatically push the most recent stashed changes run: 202 | 203 | git config --add private.wip.push "stash@{0} stashed" 204 | 205 | To fetch them all: 206 | 207 | git config --add remote.origin.fetch "+refs/wip/*:refs/wip/*" 208 | 209 | To fetch only yours: 210 | 211 | git config --add remote.origin.fetch "fetch = +refs/wip/user@example.com/*:refs/wip/*" 212 | 213 | Well, that's it. Except, backup without history, is not a real backup. Let's 214 | add history... 215 | 216 | #### Backup with history 217 | 218 | I am working on a feature branch and I need to rebase frequently. 219 | 220 | I want a copy of my work stored on the server and I want to have full history of 221 | changes if I need to go back after a bad rebase. 222 | 223 | git backup BRANCH 224 | git backup 225 | 226 | Let's add the configuration: 227 | 228 | [private "backup"] 229 | tsfmt = "%Y%m%d-%H%M" 230 | fmt = "$EMAIL/$DST/$TS" 231 | 232 | [alias] 233 | backup = private-push --id backup 234 | 235 | Add refs to backup by default: 236 | 237 | git config --add private.wip.push wip 238 | 239 | Now running `git backup` will push `wip` branch as 240 | `refs/backup/user@example.com/wip/20160310-1135`. 241 | 242 | Hooray! 243 | 244 | ## Configuration 245 | 246 | - `private.$ID.*` - configuration for particular private space 247 | - `private.*` - default options 248 | 249 | It may be useful to define global defaults: 250 | 251 | git config --global private.tsfmt "%Y/%m/%d/%H%M/" 252 | 253 | The configuration options are: 254 | 255 | - `private.id` - default ID. 256 | - `*.fmt` - path format. Defaults to `$TS$DST`. 257 | Strings `$TS`, `$USER`, `$EMAIL` and `SDST` are replaced with corresponding 258 | values. These strings are replaced in `$TS` but not in any other of the 259 | values. 260 | - `*.tsfmt` - timestamp format. This defaults to `%Y/%m/%d/%H/`. 261 | - `*.path` - path within remote. This defaults to `$ID/`. 262 | - `*.remote` - remote where private refs are kept. Defaults to `$ID`. 263 | - `*.push` - `SRC [DST]` couple to use when not given on command line. There 264 | may be multiple of them. 265 | - `*.force` - if not empty force push if remote ref already exists. This may 266 | be overridden on command line by `--no-force` option. 267 | 268 | For example to define origin for "WIP" space one can use: 269 | 270 | git config private.wip.remote origin 271 | 272 | Add a default push "pair" (using default destination): 273 | 274 | git config --add private.wip.push master 275 | 276 | Add a default push "pair" (using different destination): 277 | 278 | git config --add private.wip.push "stash@{0} stashed" 279 | 280 | In the `.git/config` it looks like: 281 | 282 | [private "wip"] 283 | remote = origin 284 | path = wip/nb1/ 285 | tsfmt = 0/ # Use constant. Default would be used if empty. 286 | push = master 287 | push = "stash@{0} stashed" 288 | 289 | [remote "origin"] 290 | fetch = +refs/heads/*:refs/remotes/origin/* 291 | fetch = +refs/wip/*:refs/wip/origin/* 292 | -------------------------------------------------------------------------------- /git-private-add-fetch: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DEFAULT_ID='junk' 4 | 5 | usage() { 6 | echo "Usage: git-private-add-fetch [ID]" 7 | } 8 | 9 | helpme() { 10 | cat <