not set, defaults to -1, the zlib default, which is "a default
compromise between speed and compression (currently equivalent
to level 6)."
++
+Note that changing the compression level will not automatically recompress
+all existing objects. You can force recompression by passing the -F option
+to linkgit:git-repack[1].
pack.deltaCacheSize::
The maximum memory in bytes used for caching deltas in
Detect copies as well as renames. See also `--find-copies-harder`.
If `n` is specified, it has the same meaning as for `-M<n>`.
-ifndef::git-format-patch[]
---diff-filter=[(A|C|D|M|R|T|U|X|B)...[*]]::
- Select only files that are Added (`A`), Copied (`C`),
- Deleted (`D`), Modified (`M`), Renamed (`R`), have their
- type (i.e. regular file, symlink, submodule, ...) changed (`T`),
- are Unmerged (`U`), are
- Unknown (`X`), or have had their pairing Broken (`B`).
- Any combination of the filter characters (including none) can be used.
- When `*` (All-or-none) is added to the combination, all
- paths are selected if there is any file that matches
- other criteria in the comparison; if there is no file
- that matches other criteria, nothing is selected.
-endif::git-format-patch[]
-
--find-copies-harder::
For performance reasons, by default, `-C` option finds copies only
if the original file of the copy was modified in the same
number.
ifndef::git-format-patch[]
+--diff-filter=[(A|C|D|M|R|T|U|X|B)...[*]]::
+ Select only files that are Added (`A`), Copied (`C`),
+ Deleted (`D`), Modified (`M`), Renamed (`R`), have their
+ type (i.e. regular file, symlink, submodule, ...) changed (`T`),
+ are Unmerged (`U`), are
+ Unknown (`X`), or have had their pairing Broken (`B`).
+ Any combination of the filter characters (including none) can be used.
+ When `*` (All-or-none) is added to the combination, all
+ paths are selected if there is any file that matches
+ other criteria in the comparison; if there is no file
+ that matches other criteria, nothing is selected.
+
-S<string>::
Look for differences that introduce or remove an instance of
<string>. Note that this is different than the string simply
:git-pull: 1
--rebase::
- Instead of a merge, perform a rebase after fetching. If
- there is a remote ref for the upstream branch, and this branch
- was rebased since last fetched, the rebase uses that information
- to avoid rebasing non-local changes. To make this the default
- for branch `<name>`, set configuration `branch.<name>.rebase`
- to `true`.
+ Rebase the current branch on top of the upstream branch after
+ fetching. If there is a remote-tracking branch corresponding to
+ the upstream branch and the upstream branch was rebased since last
+ fetched, the rebase uses that information to avoid rebasing
+ non-local changes.
++
+See `branch.<name>.rebase` in linkgit:git-config[1] if you want to make
+`git pull` always use `{litdd}rebase` instead of merging.
+
[NOTE]
This is a potentially _dangerous_ mode of operation.
SYNOPSIS
--------
-'git repack' [-a] [-A] [-d] [-f] [-l] [-n] [-q] [--window=<n>] [--depth=<n>]
+'git repack' [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [--window=<n>] [--depth=<n>]
DESCRIPTION
-----------
linkgit:git-pack-objects[1].
-f::
+ Pass the `--no-reuse-delta` option to `git-pack-objects`, see
+ linkgit:git-pack-objects[1].
+
+-F::
Pass the `--no-reuse-object` option to `git-pack-objects`, see
linkgit:git-pack-objects[1].
DESCRIPTION
-----------
In the first and second form, copy entries from <commit> to the index.
-In the third form, set the current branch to <commit>, optionally
-modifying index and worktree to match. The <commit> defaults to HEAD
+In the third form, set the current branch head (HEAD) to <commit>, optionally
+modifying index and working tree to match. The <commit> defaults to HEAD
in all forms.
'git reset' [-q] [<commit>] [--] <paths>...::
This form resets the index entries for all <paths> to their
- state at the <commit>. (It does not affect the worktree, nor
+ state at <commit>. (It does not affect the working tree, nor
the current branch.)
+
This means that `git reset <paths>` is the opposite of `git add
<paths>`.
++
+After running `git reset <paths>` to update the index entry, you can
+use linkgit:git-checkout[1] to check the contents out of the index to
+the working tree.
+Alternatively, using linkgit:git-checkout[1] and specifying a commit, you
+can copy the contents of a path out of a commit to the index and to the
+working tree in one go.
'git reset' --patch|-p [<commit>] [--] [<paths>...]::
Interactively select hunks in the difference between the index
linkgit:git-add[1]).
'git reset' [--<mode>] [<commit>]::
- This form points the current branch to <commit> and then
- updates index and working tree according to <mode>, which must
- be one of the following:
+ This form resets the current branch head to <commit> and
+ possibly updates the index (resetting it to the tree of <commit>) and
+ the working tree depending on <mode>, which
+ must be one of the following:
+
--
--soft::
- Does not touch the index file nor the working tree at all, but
- requires them to be in a good order. This leaves all your changed
- files "Changes to be committed", as 'git status' would
- put it.
+ Does not touch the index file nor the working tree at all (but
+ resets the head to <commit>, just like all modes do). This leaves
+ all your changed files "Changes to be committed", as 'git status'
+ would put it.
--mixed::
Resets the index but not the working tree (i.e., the changed files
been updated. This is the default action.
--hard::
- Matches the working tree and index to that of the tree being
- switched to. Any changes to tracked files in the working tree
- since <commit> are lost.
+ Resets the index and working tree. Any changes to tracked files in the
+ working tree since <commit> are discarded.
--merge::
- Resets the index to match the tree recorded by the named commit,
- and updates the files that are different between the named commit
- and the current commit in the working tree.
+ Resets the index and updates the files in the working tree that are
+ different between <commit> and HEAD, but keeps those which are
+ different between the index and working tree (i.e. which have changes
+ which have not been added).
+ If a file that is different between <commit> and the index has unstaged
+ changes, reset is aborted.
++
+In other words, --merge does something like a 'git read-tree -u -m <commit>',
+but carries forward unmerged index entries.
--keep::
- Reset the index to the given commit, keeping local changes in
- the working tree since the current commit, while updating
- working tree files without local changes to what appears in
- the given commit. If a file that is different between the
- current commit and the given commit has local changes, reset
- is aborted.
+ Resets the index, updates files in the working tree that are
+ different between <commit> and HEAD, but keeps those
+ which are different between HEAD and the working tree (i.e.
+ which have local changes).
+ If a file that is different between <commit> and HEAD has local changes,
+ reset is aborted.
++
+In other words, --keep does a 2-way merge between <commit> and HEAD followed by
+'git reset --mixed <commit>'.
--
If you want to undo a commit other than the latest on a branch,
brings your index file and the working tree back to that state,
and resets the tip of the branch to that commit.
-Undo a merge or pull inside a dirty work tree::
+Undo a merge or pull inside a dirty working tree::
+
------------
$ git pull <1>
continue working a bit more, but now you think that what you have in
your working tree should be in another branch that has nothing to do
with what you committed previously. You can start a new branch and
-reset it while keeping the changes in your work tree.
+reset it while keeping the changes in your working tree.
+
------------
$ git tag start
file. For example, the first line of the first table means that if a
file is in state A in the working tree, in state B in the index, in
state C in HEAD and in state D in the target, then "git reset --soft
-target" will put the file in state A in the working tree, in state B
-in the index and in state D in HEAD.
+target" will leave the file in the working tree in state A and in the
+index in state B. It resets (i.e. moves) the HEAD (i.e. the tip of
+the current branch, if you are on one) to "target" (which has the file
+in state D).
working index HEAD target working index HEAD
----------------------------------------------------
--keep B C C
"reset --merge" is meant to be used when resetting out of a conflicted
-merge. Any mergy operation guarantees that the work tree file that is
+merge. Any mergy operation guarantees that the working tree file that is
involved in the merge does not have local change wrt the index before
-it starts, and that it writes the result out to the work tree. So if
+it starts, and that it writes the result out to the working tree. So if
we see some difference between the index and the target and also
-between the index and the work tree, then it means that we are not
+between the index and the working tree, then it means that we are not
resetting out from a state that a mergy operation left after failing
with a conflict. That is why we disallow --merge option in this case.
git show v1.0.0^\{tree\}::
Shows the tree pointed to by the tag `v1.0.0`.
+git show -s --format=%s v1.0.0^\{commit\}::
+ Shows the subject of the commit pointed to by the
+ tag `v1.0.0`.
+
git show next~10:Documentation/README::
Shows the contents of the file `Documentation/README` as
they were current in the 10th last commit of the branch
to be printed in between commits, in order for the graph history
to be drawn properly.
+
+This enables parent rewriting, see 'History Simplification' below.
++
This implies the '--topo-order' option by default, but the
'--date-order' option may also be specified.
-t::
Show the tree objects in the diff output. This implies '-r'.
+
+-s::
+ Suppress diff output.
endif::git-rev-list[]
Commit Limiting
--- /dev/null
+sigchain API
+============
+
+Code often wants to set a signal handler to clean up temporary files or
+other work-in-progress when we die unexpectedly. For multiple pieces of
+code to do this without conflicting, each piece of code must remember
+the old value of the handler and restore it either when:
+
+ 1. The work-in-progress is finished, and the handler is no longer
+ necessary. The handler should revert to the original behavior
+ (either another handler, SIG_DFL, or SIG_IGN).
+
+ 2. The signal is received. We should then do our cleanup, then chain
+ to the next handler (or die if it is SIG_DFL).
+
+Sigchain is a tiny library for keeping a stack of handlers. Your handler
+and installation code should look something like:
+
+------------------------------------------
+ void clean_foo_on_signal(int sig)
+ {
+ clean_foo();
+ sigchain_pop(sig);
+ raise(sig);
+ }
+
+ void other_func()
+ {
+ sigchain_push_common(clean_foo_on_signal);
+ mess_up_foo();
+ clean_foo();
+ }
+------------------------------------------
+
+Handlers are given the typdef of sigchain_fun. This is the same type
+that is given to signal() or sigaction(). It is perfectly reasonable to
+push SIG_DFL or SIG_IGN onto the stack.
+
+You can sigchain_push and sigchain_pop individual signals. For
+convenience, sigchain_push_common will push the handler onto the stack
+for many common signals.
git-imap-send$X: imap-send.o $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
- $(LIBS) $(OPENSSL_LINK) $(OPENSSL_LIBSSL)
+ $(LIBS) $(OPENSSL_LINK) $(OPENSSL_LIBSSL) $(LIB_4_CRYPTO)
git-http-fetch$X: revision.o http.o http-walker.o http-fetch.o $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
$(FIND) . -name '*.[hcS]' -print | xargs cscope -b
### Detect prefix changes
-TRACK_CFLAGS = $(subst ','\'',$(ALL_CFLAGS)):\
+TRACK_CFLAGS = $(CC):$(subst ','\'',$(ALL_CFLAGS)):\
$(bindir_SQ):$(gitexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)
GIT-CFLAGS: FORCE
{
int i;
int show_only = 0, remove_directories = 0, quiet = 0, ignored = 0;
- int ignored_only = 0, baselen = 0, config_set = 0, errors = 0;
+ int ignored_only = 0, config_set = 0, errors = 0;
int rm_flags = REMOVE_DIR_KEEP_NESTED_GIT;
struct strbuf directory = STRBUF_INIT;
struct dir_struct dir;
if (pathspec) {
memset(seen, 0, argc > 0 ? argc : 1);
matches = match_pathspec(pathspec, ent->name, len,
- baselen, seen);
+ 0, seen);
}
if (S_ISDIR(st.st_mode)) {
printf("Removing %s\n", qname);
if (remove_dir_recursively(&directory,
rm_flags) != 0) {
- warning("failed to remove '%s'", qname);
+ warning("failed to remove %s", qname);
errors++;
}
} else if (show_only) {
printf("Removing %s\n", qname);
}
if (unlink(ent->name) != 0) {
- warning("failed to remove '%s'", qname);
+ warning("failed to remove %s", qname);
errors++;
}
}
else
parent = commit->parents->item;
- if (allow_ff && !hashcmp(parent->object.sha1, head))
+ if (allow_ff && parent && !hashcmp(parent->object.sha1, head))
return fast_forward_to(commit->object.sha1, head);
if (parent && parse_commit(parent) < 0)
*/
static int do_lstat(const char *file_name, struct stat *buf)
{
+ int err;
WIN32_FILE_ATTRIBUTE_DATA fdata;
- if (!(errno = get_file_attr(file_name, &fdata))) {
+ if (!(err = get_file_attr(file_name, &fdata))) {
buf->st_ino = 0;
buf->st_gid = 0;
buf->st_uid = 0;
buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
return 0;
}
+ errno = err;
return -1;
}
submitTemplate = self.prepareLogMessage(template, logMessage)
if os.environ.has_key("P4DIFF"):
del(os.environ["P4DIFF"])
- diff = p4_read_pipe("diff -du ...")
+ diff = ""
+ for editedFile in editedFiles:
+ diff += p4_read_pipe("diff -du %r" % editedFile)
newdiff = ""
for newFile in filesToAdd:
# ---------------------------- Functions
#
-# Top level email generation function. This decides what type of update
-# this is and calls the appropriate body-generation routine after outputting
-# the common header
+# Function to prepare for email generation. This decides what type
+# of update this is and whether an email should even be generated.
#
-# Note this function doesn't actually generate any email output, that is
-# taken care of by the functions it calls:
-# - generate_email_header
-# - generate_create_XXXX_email
-# - generate_update_XXXX_email
-# - generate_delete_XXXX_email
-# - generate_email_footer
-#
-generate_email()
+prep_for_email()
{
# --- Arguments
oldrev=$(git rev-parse $1)
# Anything else (is there anything else?)
echo >&2 "*** Unknown type of update to $refname ($rev_type)"
echo >&2 "*** - no email generated"
- exit 1
+ return 0
;;
esac
esac
echo >&2 "*** $config_name is not set so no email will be sent"
echo >&2 "*** for $refname update $oldrev->$newrev"
- exit 0
+ return 0
fi
+ return 1
+}
+
+#
+# Top level email generation function. This calls the appropriate
+# body-generation routine after outputting the common header.
+#
+# Note this function doesn't actually generate any email output, that is
+# taken care of by the functions it calls:
+# - generate_email_header
+# - generate_create_XXXX_email
+# - generate_update_XXXX_email
+# - generate_delete_XXXX_email
+# - generate_email_footer
+#
+# Note also that this function cannot 'exit' from the script; when this
+# function is running (in hook script mode), the send_mail() function
+# is already executing in another process, connected via a pipe, and
+# if this function exits without, whatever has been generated to that
+# point will be sent as an email... even if nothing has been generated.
+#
+generate_email()
+{
# Email parameters
# The email subject will contain the best description of the ref
# that we can build from the parameters
# Output to the terminal in command line mode - if someone wanted to
# resend an email; they could redirect the output to sendmail
# themselves
- PAGER= generate_email $2 $3 $1
+ prep_for_email $2 $3 $1 && PAGER= generate_email
else
while read oldrev newrev refname
do
- generate_email $oldrev $newrev $refname $maxlines | send_mail
+ prep_for_email $oldrev $newrev $refname || continue
+ generate_email $maxlines | send_mail
done
fi
if (x->flags & EXC_FLAG_MUSTBEDIR) {
if (!dtype) {
- if (!prefixcmp(pathname, exclude))
+ if (!prefixcmp(pathname, exclude) &&
+ pathname[x->patternlen] == '/')
return to_exclude;
else
continue;
esac
strategy_opts="$strategy_opts $(git rev-parse --sq-quote "--$newopt")"
do_merge=t
- if test -n "$strategy"
- then
- strategy=recursive
- fi
;;
-s=*|--s=*|--st=*|--str=*|--stra=*|--strat=*|--strate=*|\
--strateg=*|--strategy=*|\
a pack everything in a single pack
A same as -a, and turn unreachable objects loose
d remove redundant packs, and run git-prune-packed
-f pass --no-reuse-object to git-pack-objects
+f pass --no-reuse-delta to git-pack-objects
+F pass --no-reuse-object to git-pack-objects
n do not run git-update-server-info
q,quiet be quiet
l pass --local to git-pack-objects
unpack_unreachable=--unpack-unreachable ;;
-d) remove_redundant=t ;;
-q) GIT_QUIET=t ;;
- -f) no_reuse=--no-reuse-object ;;
+ -f) no_reuse=--no-reuse-delta ;;
+ -F) no_reuse=--no-reuse-object ;;
-l) local=--local ;;
--max-pack-size|--window|--window-memory|--depth)
extra="$extra $1=$2"; shift ;;
--[no-]validate * Perform patch sanity checks. Default on.
--[no-]format-patch * understand any non optional arguments as
`git format-patch` ones.
+ --force * Send even if safety checks would prevent it.
EOT
exit(1);
my ($quiet, $dry_run) = (0, 0);
my $format_patch;
my $compose_filename;
+my $force = 0;
# Handle interactive edition of files.
my $multiedit;
"validate!" => \$validate,
"format-patch!" => \$format_patch,
"8bit-encoding=s" => \$auto_8bit_encoding,
+ "force" => \$force,
);
unless ($rc) {
default => "UTF-8");
}
+if (!$force) {
+ for my $f (@files) {
+ if (get_patch_subject($f) =~ /\*\*\* SUBJECT HERE \*\*\*/) {
+ die "Refusing to send because the patch\n\t$f\n"
+ . "has the template subject '*** SUBJECT HERE ***'. "
+ . "Pass --force if you really want to send.\n";
+ }
+ }
+}
+
my $prompting = 0;
if (!defined $sender) {
$sender = $repoauthor || $repocommitter || '';
sub send_message {
my @recipients = unique_email_list(@to);
@cc = (grep { my $cc = extract_valid_address($_);
- not grep { $cc eq $_ } @recipients
+ not grep { $cc eq $_ || $_ =~ /<\Q${cc}\E>$/ } @recipients
}
map { sanitize_address($_) }
@cc);
s/'\''/'\''\\'\'\''/g
h
s/^author \([^<]*\) <[^>]*> .*$/\1/
- s/'\''/'\''\'\'\''/g
s/.*/GIT_AUTHOR_NAME='\''&'\''/p
g
s/^author [^<]* <\([^>]*\)> .*$/\1/
- s/'\''/'\''\'\'\''/g
s/.*/GIT_AUTHOR_EMAIL='\''&'\''/p
g
s/^author [^<]* <[^>]*> \(.*\)$/\1/
- s/'\''/'\''\'\'\''/g
s/.*/GIT_AUTHOR_DATE='\''&'\''/p
q
cat >expected <<-\EOF &&
100644 77f0ba1734ed79d12881f81b36ee134de6a3327b 0 init.t
100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 sub/added
+ 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 subsub/added
EOF
cat >expected.swt <<-\EOF &&
H init.t
H sub/added
+ H subsub/added
EOF
test_commit init &&
echo modified >>init.t &&
- mkdir sub &&
- touch sub/added &&
- git add init.t sub/added &&
+ mkdir sub subsub &&
+ touch sub/added subsub/added &&
+ git add init.t sub/added subsub/added &&
git commit -m "modified and added" &&
git tag top &&
git rm sub/added &&
cat >expected.swt-noinit <<-\EOF &&
S init.t
H sub/added
+ S subsub/added
EOF
echo sub/ > .git/info/sparse-checkout &&
cat >expected.swt-nosub <<-\EOF &&
H init.t
S sub/added
+ S subsub/added
EOF
echo init.t >.git/info/sparse-checkout &&
esac
'
+test_expect_success 'rebase -s funny -Xopt' '
+ test_when_finished "rm -fr test-bin funny.was.run" &&
+ mkdir test-bin &&
+ cat >test-bin/git-merge-funny <<-EOF &&
+ #!$SHELL_PATH
+ case "\$1" in --opt) ;; *) exit 2 ;; esac
+ shift &&
+ >funny.was.run &&
+ exec git merge-recursive "\$@"
+ EOF
+ chmod +x test-bin/git-merge-funny &&
+ git reset --hard &&
+ git checkout -b test-funny master^ &&
+ test_commit funny &&
+ (
+ PATH=./test-bin:$PATH
+ git rebase -s funny -Xopt master
+ ) &&
+ test -f funny.was.run
+'
+
test_done
test_must_fail git cherry-pick --ff -m 3 C
'
+test_expect_success 'cherry pick a root commit with --ff' '
+ git reset --hard first -- &&
+ git rm file1 &&
+ echo first >file2 &&
+ git add file2 &&
+ git commit --amend -m "file2" &&
+ git cherry-pick --ff first &&
+ test "$(git rev-parse --verify HEAD)" = "1df192cd8bc58a2b275d842cede4d221ad9000d1"
+'
+
test_done
test_cmp expected actual
'
+# Note that the patches in this test are deliberately out of order; we
+# want to make sure it works even if the cover-letter is not in the
+# first mail.
+test_expect_success 'refusing to send cover letter template' '
+ clean_fake_sendmail &&
+ rm -fr outdir &&
+ git format-patch --cover-letter -2 -o outdir &&
+ test_must_fail git send-email \
+ --from="Example <nobody@example.com>" \
+ --to=nobody@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ outdir/0002-*.patch \
+ outdir/0000-*.patch \
+ outdir/0001-*.patch \
+ 2>errors >out &&
+ grep "SUBJECT HERE" errors &&
+ test -z "$(ls msgtxt*)"
+'
+
+test_expect_success '--force sends cover letter template anyway' '
+ clean_fake_sendmail &&
+ rm -fr outdir &&
+ git format-patch --cover-letter -2 -o outdir &&
+ git send-email \
+ --force \
+ --from="Example <nobody@example.com>" \
+ --to=nobody@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ outdir/0002-*.patch \
+ outdir/0000-*.patch \
+ outdir/0001-*.patch \
+ 2>errors >out &&
+ ! grep "SUBJECT HERE" errors &&
+ test -n "$(ls msgtxt*)"
+'
+
test_done