git-clean - Remove untracked files from the working tree
Synopsis
git clean [-d] [-f] [-i] [-n] [-q] [-e <pattern>] [-x | -X] [--] <path>…
Description
Cleans the working tree by recursively removing files that are not under version control, starting from the current directory.
Normally, only files unknown to Git are removed, but if the -x
option is specified, ignored files are also removed. This can, for example, be useful to remove all build products.
If any optional <path>...
arguments are given, only those paths are affected.
Step 1 is to show what will be deleted by using the -n
option:
# Print out the list of files and directories which will be removed (dry run)
git clean -n -d
Clean Step - beware: this will delete files:
# Delete the files from the repository
git clean -f
- To remove directories, run
git clean -f -d
or git clean -fd
- To remove ignored files, run
git clean -f -X
or git clean -fX
- To remove ignored and non-ignored files, run
git clean -f -x
or git clean -fx
Note the case difference on the X
for the two latter commands.
If clean.requireForce
is set to "true" (the default) in your configuration, one needs to specify -f
otherwise nothing will actually happen.
Again see the git-clean
docs for more information.
Options
-f
, --force
If the Git configuration variable clean.requireForce is not set to
false, git clean will refuse to run unless given -f
, -n
or -i
.
-x
Don’t use the standard ignore rules read from .gitignore (per
directory) and $GIT_DIR/info/exclude
, but do still use the ignore
rules given with -e
options. This allows removing all untracked files,
including build products. This can be used (possibly in conjunction
with git reset) to create a pristine working directory to test a clean
build.
-X
Remove only files ignored by Git. This may be useful to rebuild
everything from scratch, but keep manually created files.
-n
, --dry-run
Don’t actually remove anything, just show what would be done.
-d
Remove untracked directories in addition to untracked files. If an
untracked directory is managed by a different Git repository, it is
not removed by default. Use -f
option twice if you really want to
remove such a directory.
Assuming the hash of the commit you want is c5f567
:
git checkout c5f567 -- file1/to/restore file2/to/restore
The git checkout man page gives more information.
If you want to revert to the commit before c5f567
, append ~1
(where 1 is the number of commits you want to go back, it can be anything):
git checkout c5f567~1 -- file1/to/restore file2/to/restore
As a side note, I've always been uncomfortable with this command because it's used for both ordinary things (changing between branches) and unusual, destructive things (discarding changes in the working directory).
There is also a new git restore
command that is specifically designed for restoring working copy files that have been modified. If your git is new enough you can use this command, but the documentation comes with a warning:
THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
Best Solution
On the specific instance of a config file, I would agree with Ron's answer:
a config should be "private" to your workspace (hence "ignored", as in "declared in a
.gitignore
file").You may have a config file template with tokenized values in it, and a script transforming that
config.template
file into a private (and ignored) config file.However, that specific remark does not answer what is a broader more general question, i.e. your question(!):
This kind of merge is a "copy merge", in which you will always copy 'ours' or 'theirs' version of a file whenever there is a conflict.
For "a file" (a file in general, not speaking of a "config" file, since it is a bad example), you would achieve that with a custom script called through merges.
Git will call that script because you will have define a gitattributes value, which defines a custom merge driver.
The "custom merge driver" is, in this case, a very simple script which basically will keep unchanged the current version, hence allowing you to always select your local version.
IE., As noted by Ciro Santilli:
Let's test that in a simple scenario, with a msysgit 1.6.3 on Windows, in a mere DOS session:
Now, let's make two files, which will both have conflicts, but which will be merged differently.
We will introduce a "conflict" in the content of both those files in two different git branches:
Now, let's try to merge "hisBranch" upon "myBranch", with:
dirWithCopyMerge\b.txt
where I always want to keep my version ofb.txt
.Since the merge occurs in '
MyBranch
', we will switch back to it, and add the 'gitattributes
' directives which will customize the merge behavior.We have a
.gitattributes
file defined in thedirWithCopyMerge
directory (defined only in the branch where the merge will occurs:myBranch
), and we have a.git\config
file which now contains a merge driver.If you do not yet define keepMine.sh, and launch the merge anyway, here is what you get.
That is fine:
a.txt
is ready to be merged and has conflict in itb.txt
is still untouched, since the merge driver is supposed to take care of it (due to the directive in the.gitattributes
file in its directory).Define a
keepMine.sh
anywhere in your%PATH%
(or$PATH
for our Unix friend. I do both of course: I have an Ubuntu session in a VirtualBox session)As commented by lrkwz, and described in the "Merge Strategies" section of Customizing Git - Git Attributes, you can replace the shell script with the shell command
true
.But in the general case, you can define a script file:
keepMine.sh
(that was one simple merge driver ;) (Even simpler in that case, use
true
)(If you wanted to keep the other version, just add before the
exit 0
line:cp -f $3 $2
.That's it. You merge driver would aways keep the version coming from the other branch, overriding any local change)
Now, let's retry the merge from the beginning:
The merge fails... only for a.txt.
Edit a.txt and leave the line from 'hisBranch', then:
Let's check that b.txt has been preserved during this merge
The last commit does represent the full merge:
(The line beginning with Merge does prove that)
Consider you can define, combine and/or overwrite merge driver, as Git will:
<dir>/.gitattributes
(which is in the same directory as the path in question): will prevail upon the other.gitattributes
in directories.gitattributes
(which is in the parent directory), will only set directives if not already set$GIT_DIR/info/attributes
. This file is used to override the in-tree settings. It will overwrite<dir>/.gitattributes
directives.By "combining", I mean "aggregate" multiple merge driver.
Nick Green tries, in the comments, to actually combine merge drivers: see "Merge pom's via python git driver".
However, as mentioned in his other question, it only works in case of conflicts (concurrent modification in both branches).