Test commit
[cogito/jonas.git] / cg-restore
blob19b4027db9931ad040374d94630d8cbb679e1c85
1 #!/usr/bin/env bash
3 # Restore files in the working tree to the given state
4 # Copyright (c) Petr Baudis, 2005
6 # Restore given files to their original state. It recovers any files
7 # (or files passed as arguments to the command, respectively) removed
8 # locally whose removal was not recorded by `cg-rm`.
10 # If passed the -f parameter, it restores the files to their state
11 # as of the last commit (including bringing files removed with
12 # `cg-rm` back to life).
14 # If passed the -r parameter, it will not restore the file as of the
15 # last commit, but to the state in the given commit, tree, or blob.
16 # The list of files is mandatory in this case.
18 # For the "restore-to-last-commit" usage, this command is
19 # complementary to the `cg-reset` command, which forcefully abandons
20 # all the changes in the working tree and restores everything to
21 # a proper state (including unseeking, cancelling merge in progress
22 # and rebuilding indexes).
24 # OPTIONS
25 # -------
26 # -f:: Undo local changes since last commit
27 # Restore even locally modified files to the version as of
28 # the last commit. Take care!
30 # -r COMMIT_ID:: Restore files to given COMMIT_ID
31 # -r TREE_ID:: Restore files to given TREE_ID
32 # -r BLOB_ID:: Restore files to given BLOB_ID
33 # Restore the file to the state appropriate to the given ID.
34 # The list of files to recover is mandatory in this case.
36 # Testsuite: Marginal (part of t9202-merge-on-dirty)
38 USAGE="cg-restore [-f] [-r ID] [FILE]..."
40 . "${COGITO_LIB}"cg-Xlib || exit 1
42 force=
43 objid=
44 while optparse; do
45 if optparse -f; then
46 force=-f
47 elif optparse -r=; then
48 objid="$(cg-object-id -n "${OPTARG}")" || exit 1
49 else
50 optfail
52 done
54 ret=0
56 if [ "$ARGS" ]; then
57 if [ "$objid" ]; then
58 objtype="$(git-cat-file -t "$objid")"
59 if [ "$objtype" = "commit" ]; then
60 objid="$(cg-object-id -t "$objid")"
61 objtype="tree"
63 else
64 objid="$(cg-object-id -t)"
65 objtype="tree"
68 files=()
69 if [ -n "$force" ]; then
70 for file in "${ARGS[@]}"; do
71 files[${#files[@]}]="${_git_relpath}$file"
72 done
73 else
74 # Not forcing, filter out existing files
75 for file in "${ARGS[@]}"; do
76 if [ -e "${_git_relpath}$file" ]; then
77 echo "Error: File $file already exists; use -f to override" >&2
78 ret=2
79 continue
81 files[${#files[@]}]="${_git_relpath}$file"
82 done
83 [ ${#files[@]} -ge 1 ] || die "no files suitable for restoring left"
86 if [ "$objtype" = "tree" ]; then
87 TMPFILE="$(mktemp -t gitrestore.XXXXXX)" || exit 1
88 if ! git-ls-tree -r "$objid" "${files[@]}" |
89 sed -ne 's/^\([0-7]*\) blob \(.*\)$/\1 \2/p' |
90 ( ret=0; while read mode id name; do
91 echo "Restoring file ${name#$_git_relpath}"
92 # TODO: Use git-update-index --index-info when we
93 # will depend on git new enough. --pasky
94 if ! git-update-index --add --cacheinfo "$mode" "$id" "$name"; then
95 echo "Error: Cannot mark ${name#$_git_relpath} for update" >&2
96 ret=1
97 continue
98 else
99 echo "$name" >>$TMPFILE
101 done; exit $ret ); then
102 ret=$?
103 # When we'll do --index-info which should be atomic:
104 #|| {
105 # echo "Fatal: git-update-index failed, cancelling the whole operation (restored nothing)" >&2
106 # exit $?
109 cat "$TMPFILE" | tr '\n' '\0' | xargs -0 git-checkout-index -u $force -- || ret=1
110 rm "$TMPFILE"
112 elif [ "$objtype" = "blob" ]; then
113 [ "${#files[@]}" -gt 1 ] && warn "restoring multiple files to a single blob"
114 for file in "${files[@]}"; do
115 echo "Restoring file ${file#$_git_relpath}"
116 warn "file ${file#$_git_relpath} likely will not have correct permissions"
117 git-cat-file blob "$objid" >"$file"
118 git-update-index -- "$file" || ret=1
119 done
122 else # no arguments - much weaker
123 [ "$objid" ] && die "you need to pass an explicit list of files to -r"
124 [ "$_git_relpath" ] && die "cannot restore files en masse in subdirectories yet"
125 if [ "$(git-ls-files --deleted)" ]; then
126 git-ls-files --deleted | sed "s/^/Restoring file /"
128 git-checkout-index -u -q -a $force
131 exit $ret