git-annex (10.20230627) UNRELEASED; urgency=medium
* reinject: Added --guesskeys option.
+ * diffdriver: Added --text option for easy diffing of the contents of
+ annexed text files.
-- Joey Hess <id@joeyh.name> Mon, 26 Jun 2023 13:10:40 -0400
{- git-annex command
-
- - Copyright 2014-2021 Joey Hess <id@joeyh.name>
+ - Copyright 2014-2023 Joey Hess <id@joeyh.name>
-
- Licensed under the GNU AGPL version 3 or higher.
-}
cmd :: Command
cmd = dontCheck repoExists $
command "diffdriver" SectionPlumbing
- "external git diff driver shim"
- ("-- cmd --") (withParams seek)
+ "git diff driver"
+ ("-- cmd --") (seek <$$> optParser)
-seek :: CmdParams -> CommandSeek
-seek = withWords (commandAction . start)
+data Options = Options
+ { textDiff :: Bool
+ , restOptions :: CmdParams
+ }
-start :: [String] -> CommandStart
+optParser :: CmdParamsDesc -> Parser Options
+optParser desc = Options
+ <$> switch
+ ( long "text"
+ <> help "diff text files with diff(1)"
+ )
+ <*> cmdParams desc
+
+seek :: Options -> CommandSeek
+seek = commandAction . start
+
+start :: Options -> CommandStart
start opts = do
let (req, differ) = parseReq opts
void $ liftIO . exitBool =<< liftIO . differ =<< fixupReq req
, rNewMode req
]
-parseReq :: [String] -> (Req, Differ)
-parseReq opts = case separate (== "--") opts of
- (c:ps, l) -> (mk l, externalDiffer c ps)
- ([],_) -> badopts
+parseReq :: Options -> (Req, Differ)
+parseReq opts
+ | textDiff opts = (mk (restOptions opts), textDiffer)
+ | otherwise = case separate (== "--") (restOptions opts) of
+ (c:ps, l) -> (mk l, externalDiffer c ps)
+ ([],_) -> badopts
where
mk (path:old_file:old_hex:old_mode:new_file:new_hex:new_mode:[]) =
Req
mk (unmergedpath:[]) = UnmergedReq { rPath = unmergedpath }
mk _ = badopts
- badopts = giveup $ "Unexpected input: " ++ unwords opts
+ badopts = giveup $ "Unexpected input: " ++ unwords (restOptions opts)
{- Check if either file is a symlink to a git-annex object,
- which git-diff will leave as a normal file containing the link text.
externalDiffer :: String -> [String] -> Differ
externalDiffer c ps = \req -> boolSystem c (map Param ps ++ serializeReq req )
+
+textDiffer :: Differ
+textDiffer req = do
+ putStrLn ("diff a/" ++ rPath req ++ " b/" ++ rPath req)
+ -- diff exits nonzero on difference, so ignore exit status
+ void $ boolSystem "diff"
+ [ Param "-u"
+ , Param (rOldFile req)
+ , Param (rNewFile req)
+ ]
+ return True
# NAME
-git-annex diffdriver - external git diff driver shim
+git-annex diffdriver - git diff driver
# SYNOPSIS
+git annex diffdriver --text
+
git annex diffdriver `-- cmd --opts --`
# DESCRIPTION
-This is an external git diff driver shim. Normally, when using `git diff`
-with an external diff driver, it will not see the contents of annexed
-files, since git passes to it the git-annex symlinks or pointer files.
-This command works around the problem, by running the
-real external diff driver, and passing it the paths to the annexed content.
+Normally, `git diff` when run on annexed files displays the changes that
+are staged in git, eg annex symlinks and pointers. This command allows
+`git diff` to diff the content of annexed files instead.
+
+This command can be used either as a simple text differ,
+or as a shim that runs an external git diff driver.
-To use this, you will need to have installed some git external diff driver
-command. This is not the regular diff command; it takes a git-specific
-input. See git's documentation of `GIT_EXTERNAL_DIFF` and
+If some of your annexed files are textual in form, and can be usefully
+diffed with diff(1), you can configure git to use this command to diff
+them, by configuring `.gitattributes` to contain eg `*.txt diff=annextextdiff`
+and setting `git config diff.annextextdiff.command "git annex diffdriver --text"`
+
+If your annexed files are not textual in form, you will need an external
+diff driver program that is able to diff the file format(s) you use.
+See git's documentation of `GIT_EXTERNAL_DIFF` and
gitattributes(5)'s documentation of external diff drivers.
-Configure git to use "git-annex diffdriver -- cmd params --"
+Normally, when using `git diff` with an external diff driver, it will not
+see the contents of annexed files, since git passes to it the git-annex
+symlinks or pointer files. This command works around the problem, by
+running the real external diff driver, and passing it the paths to the
+annexed content. Configure git to use "git-annex diffdriver -- cmd params --"
as the external diff driver, where cmd is the external diff
driver you want it to run, and params are any extra parameters to pass
to it. Note the trailing "--", which is required.
-For example, set `GIT_EXTERNAL_DIFF="git-annex diffdriver -- j-c-diff --"`
+For example, to use the j-c-diff program as the external diff driver,
+set `GIT_EXTERNAL_DIFF="git-annex diffdriver -- j-c-diff --"`
# OPTIONS
-Normally "--" followed by the diff driver command, its options,
-and another "--"
+To diff text files with diff(1), use the "--text" option.
+
+To use an external diff driver command, the options must start with
+"--" followed by the diff driver command, its options, and another "--"
Also the [[git-annex-common-options]](1) can be used.
* `diffdriver`
- This can be used to make `git diff` use an external diff driver with
- annexed files.
+ This can be used to make `git diff` diff the content of annexed files.
See [[git-annex-diffdriver]](1) for details.
Cheers, Yann
PS: Thank you very much for git-annex, it's awesome! I'm giving a git-annex workshop next weekend [@Tuebix](https://cfp.tuebix.org/tuebix-2023/talk/review/GWRP3UKE3VFKVDG8RNQ8ZZPCZPNZYYWM), really looking forward to it.
+
+> [[fixed|done]] --[[Joey]]
--- /dev/null
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2023-06-28T17:43:19Z"
+ content="""
+This works:
+
+ echo * diff=text >>.gitattributes
+ git config diff.text.command "git-annex diffdriver -- sh -c 'echo diff a/\$0 b/\$0; echo \$0; diff -u \$1 \$4 || true' --"
+
+Unfortunatly, the textconv approach will not work for locked files, because
+git does not apply the textconv to symlinks. It could be made to work for
+unlocked files but the above works for all annexed files.
+
+diffing like this is only useful on text files, and most annexed files
+are not text files. That's why the diffdriver command focuses on using some
+external diff driver that knows how to diff whatever type of binary file is
+being stored in git-annex. So this should certianly not be enabled by
+default. It makes sense to enable it in .gitattributes when you have
+annexed some textual files.
+
+That command is a bit hard to come up with, with the complex shell quoting.
+So rather than try to document it, I made an easier way to do the same
+thing:
+
+ echo * diff=text >>.gitattributes
+ git config diff.text.command "git annex diffdriver --text"
+"""]]