diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -216,13 +216,14 @@
 ```
 niv - dependency manager for Nix projects
 
-version: 0.2.16
+version: 0.2.17
 
 Usage: niv [-s|--sources-file FILE] COMMAND
 
 Available options:
   -s,--sources-file FILE   Use FILE instead of nix/sources.json
   -h,--help                Show this help text
+  --version                Print version
 
 Available commands:
   init                     Initialize a Nix project. Existing files won't be
@@ -246,7 +247,7 @@
 
 Usage: niv add PACKAGE [-n|--name NAME] ([-a|--attribute KEY=VAL] |
                [-s|--string-attribute KEY=VAL] | [-b|--branch BRANCH] |
-               [-o|--owner OWNER] | [-r|--repo REPO] | [-v|--version VERSION] |
+               [-o|--owner OWNER] | [-r|--rev REV] | [-v|--version VERSION] |
                [-t|--template URL] | [-T|--type TYPE])
   Add a GitHub dependency
 
@@ -258,7 +259,7 @@
                            Set the package spec attribute <KEY> to <VAL>.
   -b,--branch BRANCH       Equivalent to --attribute branch=<BRANCH>
   -o,--owner OWNER         Equivalent to --attribute owner=<OWNER>
-  -r,--repo REPO           Equivalent to --attribute repo=<REPO>
+  -r,--rev REV             Equivalent to --attribute rev=<REV>
   -v,--version VERSION     Equivalent to --attribute version=<VERSION>
   -t,--template URL        Used during 'update' when building URL. Occurrences
                            of <foo> are replaced with attribute 'foo'.
@@ -284,8 +285,8 @@
 
 Usage: niv update [PACKAGE] ([-a|--attribute KEY=VAL] |
                   [-s|--string-attribute KEY=VAL] | [-b|--branch BRANCH] |
-                  [-o|--owner OWNER] | [-r|--repo REPO] | [-v|--version VERSION]
-                  | [-t|--template URL] | [-T|--type TYPE])
+                  [-o|--owner OWNER] | [-r|--rev REV] | [-v|--version VERSION] |
+                  [-t|--template URL] | [-T|--type TYPE])
   Update dependencies
 
 Available options:
@@ -295,7 +296,7 @@
                            Set the package spec attribute <KEY> to <VAL>.
   -b,--branch BRANCH       Equivalent to --attribute branch=<BRANCH>
   -o,--owner OWNER         Equivalent to --attribute owner=<OWNER>
-  -r,--repo REPO           Equivalent to --attribute repo=<REPO>
+  -r,--rev REV             Equivalent to --attribute rev=<REV>
   -v,--version VERSION     Equivalent to --attribute version=<VERSION>
   -t,--template URL        Used during 'update' when building URL. Occurrences
                            of <foo> are replaced with attribute 'foo'.
@@ -315,8 +316,8 @@
 
 Usage: niv modify PACKAGE [-n|--name NAME] ([-a|--attribute KEY=VAL] |
                   [-s|--string-attribute KEY=VAL] | [-b|--branch BRANCH] |
-                  [-o|--owner OWNER] | [-r|--repo REPO] | [-v|--version VERSION]
-                  | [-t|--template URL] | [-T|--type TYPE])
+                  [-o|--owner OWNER] | [-r|--rev REV] | [-v|--version VERSION] |
+                  [-t|--template URL] | [-T|--type TYPE])
   Modify dependency attributes without performing an update
 
 Available options:
@@ -327,7 +328,7 @@
                            Set the package spec attribute <KEY> to <VAL>.
   -b,--branch BRANCH       Equivalent to --attribute branch=<BRANCH>
   -o,--owner OWNER         Equivalent to --attribute owner=<OWNER>
-  -r,--repo REPO           Equivalent to --attribute repo=<REPO>
+  -r,--rev REV             Equivalent to --attribute rev=<REV>
   -v,--version VERSION     Equivalent to --attribute version=<VERSION>
   -t,--template URL        Used during 'update' when building URL. Occurrences
                            of <foo> are replaced with attribute 'foo'.
diff --git a/niv.cabal b/niv.cabal
--- a/niv.cabal
+++ b/niv.cabal
@@ -4,10 +4,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: f39c0a003ea2dd491b1c3c9471b0cf38dc4c294778271fa0771ab8afe5266ec0
+-- hash: 4857c6cf14357571406715c9ab94a54fbc920e9ae18dd7b647b8f25186023aaa
 
 name:           niv
-version:        0.2.16
+version:        0.2.17
 synopsis:       Easy dependency management for Nix projects
 description:    Easy dependency management for Nix projects.
 category:       Development
diff --git a/nix/sources.nix b/nix/sources.nix
--- a/nix/sources.nix
+++ b/nix/sources.nix
@@ -6,25 +6,33 @@
   # The fetchers. fetch_<type> fetches specs of type <type>.
   #
 
-  fetch_file = pkgs: spec:
-    if spec.builtin or true then
-      builtins_fetchurl { inherit (spec) url sha256; }
-    else
-      pkgs.fetchurl { inherit (spec) url sha256; };
+  fetch_file = pkgs: name: spec:
+    let
+      name' = sanitizeName name + "-src";
+    in
+      if spec.builtin or true then
+        builtins_fetchurl { inherit (spec) url sha256; name = name'; }
+      else
+        pkgs.fetchurl { inherit (spec) url sha256; name = name'; };
 
   fetch_tarball = pkgs: name: spec:
     let
-      ok = str: ! builtins.isNull (builtins.match "[a-zA-Z0-9+-._?=]" str);
-      # sanitize the name, though nix will still fail if name starts with period
-      name' = stringAsChars (x: if ! ok x then "-" else x) "${name}-src";
+      name' = sanitizeName name + "-src";
     in
       if spec.builtin or true then
         builtins_fetchTarball { name = name'; inherit (spec) url sha256; }
       else
         pkgs.fetchzip { name = name'; inherit (spec) url sha256; };
 
-  fetch_git = spec:
-    builtins.fetchGit { url = spec.repo; inherit (spec) rev ref; };
+  fetch_git = name: spec:
+    let
+      ref =
+        if spec ? ref then spec.ref else
+          if spec ? branch then "refs/heads/${spec.branch}" else
+            if spec ? tag then "refs/tags/${spec.tag}" else
+              abort "In git source '${name}': Please specify `ref`, `tag` or `branch`!";
+    in
+      builtins.fetchGit { url = spec.repo; inherit (spec) rev; inherit ref; };
 
   fetch_local = spec: spec.path;
 
@@ -40,11 +48,21 @@
   # Various helpers
   #
 
+  # https://github.com/NixOS/nixpkgs/pull/83241/files#diff-c6f540a4f3bfa4b0e8b6bafd4cd54e8bR695
+  sanitizeName = name:
+    (
+      concatMapStrings (s: if builtins.isList s then "-" else s)
+        (
+          builtins.split "[^[:alnum:]+._?=-]+"
+            ((x: builtins.elemAt (builtins.match "\\.*(.*)" x) 0) name)
+        )
+    );
+
   # The set of packages used when specs are fetched using non-builtins.
-  mkPkgs = sources:
+  mkPkgs = sources: system:
     let
       sourcesNixpkgs =
-        import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) {};
+        import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) { inherit system; };
       hasNixpkgsPath = builtins.any (x: x.prefix == "nixpkgs") builtins.nixPath;
       hasThisAsNixpkgsPath = <nixpkgs> == ./.;
     in
@@ -64,9 +82,9 @@
 
     if ! builtins.hasAttr "type" spec then
       abort "ERROR: niv spec ${name} does not have a 'type' attribute"
-    else if spec.type == "file" then fetch_file pkgs spec
+    else if spec.type == "file" then fetch_file pkgs name spec
     else if spec.type == "tarball" then fetch_tarball pkgs name spec
-    else if spec.type == "git" then fetch_git spec
+    else if spec.type == "git" then fetch_git name spec
     else if spec.type == "local" then fetch_local spec
     else if spec.type == "builtin-tarball" then fetch_builtin-tarball name
     else if spec.type == "builtin-url" then fetch_builtin-url name
@@ -98,25 +116,29 @@
 
   # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269
   stringAsChars = f: s: concatStrings (map f (stringToCharacters s));
+  concatMapStrings = f: list: concatStrings (map f list);
   concatStrings = builtins.concatStringsSep "";
 
+  # https://github.com/NixOS/nixpkgs/blob/8a9f58a375c401b96da862d969f66429def1d118/lib/attrsets.nix#L331
+  optionalAttrs = cond: as: if cond then as else {};
+
   # fetchTarball version that is compatible between all the versions of Nix
-  builtins_fetchTarball = { url, name, sha256 }@attrs:
+  builtins_fetchTarball = { url, name ? null, sha256 }@attrs:
     let
       inherit (builtins) lessThan nixVersion fetchTarball;
     in
       if lessThan nixVersion "1.12" then
-        fetchTarball { inherit name url; }
+        fetchTarball ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; }))
       else
         fetchTarball attrs;
 
   # fetchurl version that is compatible between all the versions of Nix
-  builtins_fetchurl = { url, sha256 }@attrs:
+  builtins_fetchurl = { url, name ? null, sha256 }@attrs:
     let
       inherit (builtins) lessThan nixVersion fetchurl;
     in
       if lessThan nixVersion "1.12" then
-        fetchurl { inherit url; }
+        fetchurl ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; }))
       else
         fetchurl attrs;
 
@@ -135,7 +157,8 @@
   mkConfig =
     { sourcesFile ? if builtins.pathExists ./sources.json then ./sources.json else null
     , sources ? if isNull sourcesFile then {} else builtins.fromJSON (builtins.readFile sourcesFile)
-    , pkgs ? mkPkgs sources
+    , system ? builtins.currentSystem
+    , pkgs ? mkPkgs sources system
     }: rec {
       # The sources, i.e. the attribute set of spec name to spec
       inherit sources;
diff --git a/src/Niv/Cli.hs b/src/Niv/Cli.hs
--- a/src/Niv/Cli.hs
+++ b/src/Niv/Cli.hs
@@ -61,7 +61,7 @@
       Opts.Failure $
         Opts.parserFailure pprefs pinfo Opts.ShowHelpText mempty
     execParserPure' pprefs pinfo args = Opts.execParserPure pprefs pinfo args
-    opts = Opts.info ((,) <$> parseFindSourcesJson <*> (parseCommand <**> Opts.helper)) $ mconcat desc
+    opts = Opts.info ((,) <$> parseFindSourcesJson <*> (parseCommand <**> Opts.helper <**> versionflag)) $ mconcat desc
     desc =
       [ Opts.fullDesc,
         Opts.headerDoc $ Just $
@@ -78,6 +78,11 @@
               <> Opts.help "Use FILE instead of nix/sources.json"
           )
         <|> pure Auto
+    versionflag :: Opts.Parser (a -> a)
+    versionflag =
+      Opts.abortOption (Opts.InfoMsg (showVersion version)) $
+        mconcat
+          [Opts.long "version", Opts.hidden, Opts.help "Print version"]
 
 parseCommand :: Opts.Parser (NIO ())
 parseCommand =
@@ -176,7 +181,7 @@
             -- Imports @niv@ and @nixpkgs@
             say "Importing 'niv' ..."
             cmdAdd
-              (updateCmd githubCmd)
+              githubCmd
               (PackageName "niv")
               ( specToFreeAttrs $ PackageSpec $
                   HMS.fromList
@@ -191,7 +196,7 @@
                 let (owner, repo) = case nixpkgs' of
                       Nixpkgs o r -> (o, r)
                 cmdAdd
-                  (updateCmd githubCmd)
+                  githubCmd
                   (PackageName "nixpkgs")
                   ( specToFreeAttrs $ PackageSpec $
                       HMS.fromList
@@ -249,8 +254,8 @@
     -- implementer: it'll be tricky to have the correct arguments show up
     -- without repeating "PACKAGE PACKAGE PACKAGE" for every package type.
     parseShortcuts = parseShortcut githubCmd
-    parseShortcut cmd = uncurry (cmdAdd (updateCmd cmd)) <$> (parseShortcutArgs cmd)
-    parseCmd cmd = uncurry (cmdAdd (updateCmd cmd)) <$> (parseCmdArgs cmd)
+    parseShortcut cmd = uncurry (cmdAdd cmd) <$> (parseShortcutArgs cmd)
+    parseCmd cmd = uncurry (cmdAdd cmd) <$> (parseCmdArgs cmd)
     parseCmdAddGit =
       Opts.info (parseCmd gitCmd <**> Opts.helper) (description gitCmd)
     parseCmdAddLocal =
@@ -321,15 +326,15 @@
                 <> Opts.help "Set the package name to <NAME>"
             )
 
-cmdAdd :: Update () a -> PackageName -> Attrs -> NIO ()
-cmdAdd updateFunc packageName attrs = do
+cmdAdd :: Cmd -> PackageName -> Attrs -> NIO ()
+cmdAdd cmd packageName attrs = do
   job ("Adding package " <> T.unpack (unPackageName packageName)) $ do
     fsj <- getFindSourcesJson
     sources <- unSources <$> li (getSources fsj)
     when (HMS.member packageName sources)
       $ li
       $ abortCannotAddPackageExists packageName
-    eFinalSpec <- fmap attrsToSpec <$> li (tryEvalUpdate attrs updateFunc)
+    eFinalSpec <- fmap attrsToSpec <$> li (doUpdate attrs cmd)
     case eFinalSpec of
       Left e -> li (abortUpdateFailed [(packageName, e)])
       Right finalSpec -> do
@@ -413,12 +418,8 @@
                 Just "git" -> gitCmd
                 Just "local" -> localCmd
                 _ -> githubCmd
-          fmap attrsToSpec
-            <$> li
-              ( tryEvalUpdate
-                  (specToLockedAttrs cliSpec <> specToFreeAttrs defaultSpec)
-                  (updateCmd cmd)
-              )
+              spec = specToLockedAttrs cliSpec <> specToFreeAttrs defaultSpec
+          fmap attrsToSpec <$> li (doUpdate spec cmd)
         Nothing -> li $ abortCannotUpdateNoSuchPackage packageName
       case eFinalSpec of
         Left e -> li $ abortUpdateFailed [(packageName, e)]
@@ -438,19 +439,19 @@
               Just "git" -> gitCmd
               Just "local" -> localCmd
               _ -> githubCmd
-        finalSpec <-
-          fmap attrsToSpec
-            <$> li
-              ( tryEvalUpdate
-                  initialSpec
-                  (updateCmd cmd)
-              )
+        finalSpec <- fmap attrsToSpec <$> li (doUpdate initialSpec cmd)
         pure finalSpec
     let (failed, sources') = partitionEithersHMS esources'
     unless (HMS.null failed)
       $ li
       $ abortUpdateFailed (HMS.toList failed)
     li $ setSources fsj $ Sources sources'
+
+-- | pretty much tryEvalUpdate but we might issue some warnings first
+doUpdate :: Attrs -> Cmd -> IO (Either SomeException Attrs)
+doUpdate attrs cmd = do
+  forM_ (extraLogs cmd attrs) $ tsay
+  tryEvalUpdate attrs (updateCmd cmd)
 
 partitionEithersHMS ::
   (Eq k, Hashable k) =>
diff --git a/src/Niv/Cmd.hs b/src/Niv/Cmd.hs
--- a/src/Niv/Cmd.hs
+++ b/src/Niv/Cmd.hs
@@ -15,5 +15,7 @@
         parseCmdShortcut :: T.Text -> Maybe (PackageName, Aeson.Object),
         parsePackageSpec :: Opts.Parser PackageSpec,
         updateCmd :: Update () (),
-        name :: T.Text
+        name :: T.Text,
+        -- | Some notes to print
+        extraLogs :: Attrs -> [T.Text]
       }
diff --git a/src/Niv/Git/Cmd.hs b/src/Niv/Git/Cmd.hs
--- a/src/Niv/Git/Cmd.hs
+++ b/src/Niv/Git/Cmd.hs
@@ -31,9 +31,28 @@
       parseCmdShortcut = parseGitShortcut,
       parsePackageSpec = parseGitPackageSpec,
       updateCmd = gitUpdate',
-      name = "git"
+      name = "git",
+      extraLogs = gitExtraLogs
     }
 
+gitExtraLogs :: Attrs -> [T.Text]
+gitExtraLogs attrs = noteRef <> warnRefBranch <> warnRefTag
+  where
+    noteRef =
+      textIf (HMS.member "ref" attrs) $
+        mkNote
+          "Your source contains a `ref` attribute. Make sure your sources.nix is up-to-date and consider using a `branch` or `tag` attribute."
+    warnRefBranch =
+      textIf (member "ref" && member "branch") $
+        mkWarn
+          "Your source contains both a `ref` and a `branch`. Niv will update the `branch` but the `ref` will be used by Nix to fetch the repo."
+    warnRefTag =
+      textIf (member "ref" && member "tag") $
+        mkWarn
+          "Your source contains both a `ref` and a `tag`. The `ref` will be used by Nix to fetch the repo."
+    member x = HMS.member x attrs
+    textIf cond txt = if cond then [txt] else []
+
 parseGitShortcut :: T.Text -> Maybe (PackageName, Aeson.Object)
 parseGitShortcut txt'@(T.dropWhileEnd (== '/') -> txt) =
   -- basic heuristics for figuring out if something is a git repo
@@ -53,7 +72,7 @@
 parseGitPackageSpec :: Opts.Parser PackageSpec
 parseGitPackageSpec =
   (PackageSpec . HMS.fromList)
-    <$> many (parseRepo <|> parseRef <|> parseRev <|> parseAttr <|> parseSAttr)
+    <$> many (parseRepo <|> parseBranch <|> parseRev <|> parseAttr <|> parseSAttr)
   where
     parseRepo =
       ("repo",) . Aeson.String
@@ -67,11 +86,12 @@
           ( Opts.long "rev"
               <> Opts.metavar "SHA"
           )
-    parseRef =
-      ("ref",) . Aeson.String
+    parseBranch =
+      ("branch",) . Aeson.String
         <$> Opts.strOption
-          ( Opts.long "ref"
-              <> Opts.metavar "REF"
+          ( Opts.long "branch"
+              <> Opts.short 'b'
+              <> Opts.metavar "BRANCH"
           )
     parseAttr =
       Opts.option
@@ -112,7 +132,7 @@
           Opts.<$$> "  niv add git git@github.com:stedolan/jq"
           Opts.<$$> "  niv add git ssh://git@github.com/stedolan/jq --rev deadb33f"
           Opts.<$$> "  niv add git https://github.com/stedolan/jq.git"
-          Opts.<$$> "  niv add git --repo /my/custom/repo --name custom --ref foobar"
+          Opts.<$$> "  niv add git --repo /my/custom/repo --name custom --branch development"
     ]
 
 gitUpdate ::
@@ -121,34 +141,34 @@
   -- | latest rev and default ref
   (T.Text -> IO (T.Text, T.Text)) ->
   Update () ()
-gitUpdate latestRev' defaultRefAndHEAD' = proc () -> do
+gitUpdate latestRev' defaultBranchAndRev' = proc () -> do
   useOrSet "type" -< ("git" :: Box T.Text)
   repository <- load "repo" -< ()
   discoverRev <+> discoverRefAndRev -< repository
   where
     discoverRefAndRev = proc repository -> do
-      refAndRev <- run defaultRefAndHEAD' -< repository
-      update "ref" -< fst <$> refAndRev
-      update "rev" -< snd <$> refAndRev
+      branchAndRev <- run defaultBranchAndRev' -< repository
+      update "branch" -< fst <$> branchAndRev
+      update "rev" -< snd <$> branchAndRev
       returnA -< ()
     discoverRev = proc repository -> do
-      ref <- load "ref" -< ()
-      rev <- run' (uncurry latestRev') -< (,) <$> repository <*> ref
+      branch <- load "branch" -< ()
+      rev <- run' (uncurry latestRev') -< (,) <$> repository <*> branch
       update "rev" -< rev
       returnA -< ()
 
 -- | The "real" (IO) update
 gitUpdate' :: Update () ()
-gitUpdate' = gitUpdate latestRev defaultRefAndHEAD
+gitUpdate' = gitUpdate latestRev defaultBranchAndRev
 
 latestRev ::
   -- | the repository
   T.Text ->
-  -- | the ref/branch
+  -- | the branch
   T.Text ->
   IO T.Text
-latestRev repo ref = do
-  let gitArgs = ["ls-remote", repo, "refs/heads/" <> ref]
+latestRev repo branch = do
+  let gitArgs = ["ls-remote", repo, "refs/heads/" <> branch]
   sout <- runGit gitArgs
   case sout of
     ls@(_ : _ : _) -> abortTooMuchOutput gitArgs ls
@@ -166,14 +186,14 @@
       abortGitFailure args $ T.unlines $
         ["Git produced too much output:"] <> map ("  " <>) ls
 
-defaultRefAndHEAD ::
+defaultBranchAndRev ::
   -- | the repository
   T.Text ->
   IO (T.Text, T.Text)
-defaultRefAndHEAD repo = do
+defaultBranchAndRev repo = do
   sout <- runGit args
   case sout of
-    (l1 : l2 : _) -> (,) <$> parseRef l1 <*> parseRev l2
+    (l1 : l2 : _) -> (,) <$> parseBranch l1 <*> parseRev l2
     _ ->
       abortGitFailure args $ T.unlines $
         [ "Could not read reference and revision from stdout:"
@@ -181,11 +201,11 @@
           <> sout
   where
     args = ["ls-remote", "--symref", repo, "HEAD"]
-    parseRef l = maybe (abortNoRef args l) pure $ do
+    parseBranch l = maybe (abortNoRef args l) pure $ do
       -- ref: refs/head/master\tHEAD -> master\tHEAD
       refAndSym <- T.stripPrefix "ref: refs/heads/" l
-      let ref = T.takeWhile (/= '\t') refAndSym
-      if T.null ref then Nothing else Just ref
+      let branch = T.takeWhile (/= '\t') refAndSym
+      if T.null branch then Nothing else Just branch
     parseRev l = maybe (abortNoRev args l) pure $ do
       checkRev $ T.takeWhile (/= '\t') l
     checkRev t = if isRev t then Just t else Nothing
diff --git a/src/Niv/Git/Test.hs b/src/Niv/Git/Test.hs
--- a/src/Niv/Git/Test.hs
+++ b/src/Niv/Git/Test.hs
@@ -57,7 +57,7 @@
 test_gitUpdateRev :: IO ()
 test_gitUpdateRev = do
   interState <- evalUpdate initialState $ proc () ->
-    gitUpdate (error "should be def") defaultRefAndHEAD' -< ()
+    gitUpdate (error "should be def") defaultBranchAndHEAD' -< ()
   let interState' = HMS.map (first (\_ -> Free)) interState
   actualState <- evalUpdate interState' $ proc () ->
     gitUpdate latestRev' (error "should update") -< ()
@@ -66,14 +66,14 @@
     $ "State mismatch: " <> show actualState
   where
     latestRev' _ _ = pure "some-other-rev"
-    defaultRefAndHEAD' _ = pure ("some-ref", "some-rev")
+    defaultBranchAndHEAD' _ = pure ("some-branch", "some-rev")
     initialState =
       HMS.fromList
         [("repo", (Free, "git@github.com:nmattia/niv"))]
     expectedState =
       HMS.fromList
         [ ("repo", "git@github.com:nmattia/niv"),
-          ("ref", "some-ref"),
+          ("branch", "some-branch"),
           ("rev", "some-other-rev"),
           ("type", "git")
         ]
@@ -104,10 +104,10 @@
 -- the update
 test_gitCalledOnce :: IO ()
 test_gitCalledOnce = do
-  defaultRefAndHEAD'' <- once1 defaultRefAndHEAD'
+  defaultBranchAndHEAD'' <- once1 defaultBranchAndHEAD'
   latestRev'' <- once2 latestRev'
   interState <- evalUpdate initialState $ proc () ->
-    gitUpdate (error "should be def") defaultRefAndHEAD'' -< ()
+    gitUpdate (error "should be def") defaultBranchAndHEAD'' -< ()
   let interState' = HMS.map (first (\_ -> Free)) interState
   actualState <- evalUpdate interState' $ proc () ->
     gitUpdate latestRev'' (error "should update") -< ()
@@ -116,14 +116,14 @@
     $ "State mismatch: " <> show actualState
   where
     latestRev' _ _ = pure "some-other-rev"
-    defaultRefAndHEAD' _ = pure ("some-ref", "some-rev")
+    defaultBranchAndHEAD' _ = pure ("some-branch", "some-rev")
     initialState =
       HMS.fromList
         [("repo", (Free, "git@github.com:nmattia/niv"))]
     expectedState =
       HMS.fromList
         [ ("repo", "git@github.com:nmattia/niv"),
-          ("ref", "some-ref"),
+          ("branch", "some-branch"),
           ("rev", "some-other-rev"),
           ("type", "git")
         ]
diff --git a/src/Niv/GitHub/Cmd.hs b/src/Niv/GitHub/Cmd.hs
--- a/src/Niv/GitHub/Cmd.hs
+++ b/src/Niv/GitHub/Cmd.hs
@@ -38,7 +38,8 @@
       parseCmdShortcut = parseAddShortcutGitHub,
       parsePackageSpec = parseGitHubPackageSpec,
       updateCmd = githubUpdate',
-      name = "github"
+      name = "github",
+      extraLogs = const []
       -- TODO: here filter by type == tarball or file or builtin-
     }
 
@@ -96,7 +97,7 @@
     shortcutAttributes =
       foldr (<|>) empty $
         mkShortcutAttribute
-          <$> ["branch", "owner", "repo", "version"]
+          <$> ["branch", "owner", "rev", "version"]
     -- TODO: infer those shortcuts from 'Update' keys
     mkShortcutAttribute :: T.Text -> Opts.Parser (T.Text, Aeson.Value)
     mkShortcutAttribute = \case
diff --git a/src/Niv/Local/Cmd.hs b/src/Niv/Local/Cmd.hs
--- a/src/Niv/Local/Cmd.hs
+++ b/src/Niv/Local/Cmd.hs
@@ -27,7 +27,8 @@
       updateCmd = proc () -> do
         useOrSet "type" -< ("local" :: Box T.Text)
         returnA -< (),
-      name = "local"
+      name = "local",
+      extraLogs = const []
     }
 
 parseLocalShortcut :: T.Text -> Maybe (PackageName, Aeson.Object)
diff --git a/src/Niv/Logger.hs b/src/Niv/Logger.hs
--- a/src/Niv/Logger.hs
+++ b/src/Niv/Logger.hs
@@ -8,6 +8,9 @@
     bug,
     tsay,
     say,
+    twarn,
+    mkWarn,
+    mkNote,
     green,
     tgreen,
     red,
@@ -72,6 +75,15 @@
   -- we use `intercalate "\n"` because `unlines` prints an extra newline at
   -- the end
   liftIO $ putStrLn $ intercalate "\n" $ (indent <>) <$> lines msg
+
+mkWarn :: T.Text -> T.Text
+mkWarn w = tbold (tyellow "WARNING") <> ": " <> w
+
+twarn :: MonadIO io => T.Text -> io ()
+twarn = tsay . mkWarn
+
+mkNote :: T.Text -> T.Text
+mkNote w = tbold (tblue "NOTE") <> ": " <> w
 
 green :: S
 green str =
diff --git a/src/Niv/Sources.hs b/src/Niv/Sources.hs
--- a/src/Niv/Sources.hs
+++ b/src/Niv/Sources.hs
@@ -164,6 +164,12 @@
     V19
   | -- can be imported when there's no sources.json
     V20
+  | -- Use the source name in fetchurl
+    V21
+  | -- Stop setting `ref` and use `branch` and `tag` in sources
+    V22
+  | -- Allow to pass custom system to bootstrap niv in pure mode
+    V23
   deriving stock (Bounded, Enum, Eq)
 
 -- | A user friendly version
@@ -189,6 +195,9 @@
   V18 -> "18"
   V19 -> "19"
   V20 -> "20"
+  V21 -> "21"
+  V22 -> "22"
+  V23 -> "23"
 
 latestVersionMD5 :: T.Text
 latestVersionMD5 = sourcesVersionToMD5 maxBound
@@ -221,6 +230,9 @@
   V18 -> "bc5e6aefcaa6f9e0b2155ca4f44e5a33"
   V19 -> "543621698065cfc6a4a7985af76df718"
   V20 -> "ab4263aa63ccf44b4e1510149ce14eff"
+  V21 -> "c501eee378828f7f49828a140dbdbca3"
+  V22 -> "935d1d2f0bf95fda977a6e3a7e548ed4"
+  V23 -> "4111204b613ec688e2669516dd313440"
 
 -- | The MD5 sum of ./nix/sources.nix
 sourcesNixMD5 :: IO T.Text
@@ -234,9 +246,9 @@
 warnIfOutdated = do
   tryAny (BL8.readFile pathNixSourcesNix) >>= \case
     Left e ->
-      tsay $
-        T.unlines -- warn with tsay
-          [ T.unwords [tyellow "WARNING:", "Could not read", T.pack pathNixSourcesNix],
+      twarn $
+        T.unlines
+          [ T.unwords ["Could not read", T.pack pathNixSourcesNix],
             T.unwords ["  ", "(", tshow e, ")"]
           ]
     Right content -> do
